一、环境搭建
安装参考官方文档
EOS三个组件:
nodeos:服务端区块链节点组件
cleos:命令行接口,与区块链交互,管理钱包,管理账户,在区块链上调用方法。(很重要,相当于以太坊web3)
keosd:管理EOSIO钱包的组件。
接下来,我们将构建这些EOSIO组件,并将它们部署在一个主机,通过单个节点对网络(testnet)进行测试与配置。
构建源码
recursive参数会将所有子组件自动克隆下来,最终我们会在本地得到全部完整的源码。
git clonehttps://github.com/EOSIO/eos --recursive
cdeos && ./eosio_build.sh
构建时间较长,最终构建成功的页面如下:
[100%] Built target cleos
Scanning dependencies of target nodeos
[100%] Building CXX object programs/nodeos/CMakeFiles/nodeos.dir/main.cpp.o
[100%] Linking CXX executable chain_test
[100%] Linking CXX executable nodeos
[100%] Built target chain_test
[100%] Built target nodeos
_______ _______ _______ _________ _______
( ____ \( ___ )( ____ \\__ __/( ___ )
| ( \/| ( ) || ( \/ ) ( | ( ) |
| (__ | | | || (_____ | | | | | |
| __) | | | |(_____ ) | | | | | |
| ( | | | | ) | | | | | | |
| (____/\| (___) |/\____) |___) (___| (___) |
(_______/(_______)\_______)\_______/(_______)
EOS.IO has been successfully built. 0:32:57
To verify your installation run the following commands:
/home/liuwenbin/opt/mongodb/bin/mongod -f /home/liuwenbin/opt/mongodb/mongod.conf &
cd /home/liuwenbin/eos/build; make test
For more information:
EOS.IO website: https://eos.io
EOS.IO Telegram channel @ https://t.me/EOSProject
EOS.IO resources: https://eos.io/resources/
EOS.IO wiki: https://github.com/EOSIO/eos/wiki
跑单元测试
cd build && maketest
这一步是为了验证源码功能完整度,耗时也较久。
安装命令
sudo make install
命令会被安装在/usr/local。执行完这个命令以后,我们可以在系统任何位置进行命令启用。
启动一个单独节点
构建完成后,会在build/programs/目录中出现nodeos文件夹,这是我们要启动节点的工具。通过以下命令启动你自己的独立节点区块链
cd programs/nodeos && ./nodeos -e -p eosio --plugineosio::wallet_api_plugin --plugineosio::chain_api_plugin --plugineosio::account_history_api_plugin
这条命令中,可执行文件./nodeos后面有很多参数,好看的是后面的plugin是启动时对插件的配置,剩下的参数配置我们会在接下来介绍到。启动以后,日志打印出来相关信息:
3562788ms thread-0 chain_plugin.cpp:125 plugin_initialize ] initializing chain plugin
3562797ms thread-0 block_log.cpp:120 open ] Log is nonempty
3562798ms thread-0 block_log.cpp:123 open ] my->head->block_num(): 19
3562798ms thread-0 block_log.cpp:129 open ] Index is nonempty
3562805ms thread-0 wallet_plugin.cpp:41 plugin_initialize ] initializing wallet plugin
3562805ms thread-0 http_plugin.cpp:247 plugin_initialize ] configured http to listen on 172.168.10.6:8888
3562805ms thread-0 wallet_api_plugin.cpp:118 plugin_initialize ]
*************************************
* *
* -- Wallet NOT on localhost -- *
* - Password and/or Private Keys - *
* - are transferred unencrypted. - *
* *
*************************************
3562806ms thread-0 net_plugin.cpp:2822 plugin_initialize ] Initialize net plugin
3562806ms thread-0 net_plugin.cpp:2843 plugin_initialize ] host: 0.0.0.0 port: 9876
3562806ms thread-0 net_plugin.cpp:2915 plugin_initialize ] my node_id is fe08589261bb3e388dc5373ccc1e0289aa2b92377bd007da6aeee95fe219ac4d
3562806ms thread-0 http_plugin.cpp:225 operator() ] configured http with Access-Control-Allow-Headers : *
3562806ms thread-0 http_plugin.cpp:219 operator() ] configured http with Access-Control-Allow-Origin: *
3562806ms thread-0 main.cpp:94 main ] nodeos version cd979827
3562806ms thread-0 main.cpp:95 main ] eosio root is /home/demos/.local/share
3562807ms thread-0 chain_plugin.cpp:253 plugin_startup ] starting chain in read/write mode
3562807ms thread-0 chain_plugin.cpp:258 plugin_startup ] Blockchain started; head block is #20, genesis timestamp is 2018-03-01T12:00:00.000
3562807ms thread-0 producer_plugin.cpp:381 plugin_startup ] producer plugin: plugin_startup() begin
3562807ms thread-0 producer_plugin.cpp:388 plugin_startup ] Launching block production for 1 producers.
3562807ms thread-0 producer_plugin.cpp:401 plugin_startup ] producer plugin: plugin_startup() end
3562807ms thread-0 http_plugin.cpp:285 plugin_startup ] start listening for http requests
3562807ms thread-0 wallet_api_plugin.cpp:74 plugin_startup ] starting wallet_api_plugin
3562807ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/wallet/create
3562807ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/wallet/create_key
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/wallet/get_public_keys
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/wallet/import_key
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/wallet/list_keys
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/wallet/list_wallets
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/wallet/lock
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/wallet/lock_all
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/wallet/open
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/wallet/set_timeout
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/wallet/sign_transaction
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/wallet/unlock
3562808ms thread-0 chain_api_plugin.cpp:62 plugin_startup ] starting chain_api_plugin
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/chain/abi_bin_to_json
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/chain/abi_json_to_bin
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/chain/get_account
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/chain/get_block
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/chain/get_code
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/chain/get_currency_balance
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/chain/get_currency_stats
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/chain/get_info
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/chain/get_producers
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/chain/get_required_keys
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/chain/get_table_rows
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/chain/push_block
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/chain/push_transaction
3562808ms thread-0 http_plugin.cpp:325 add_handler ] add api url: /v1/chain/push_transactions
3562808ms thread-0 net_plugin.cpp:2927 plugin_startup ] starting listener, max clients is 25
下面来逐一分析一下这个日志内容,可以看出EOS启动私链节点是通过插件实现的,在启动私链前,要对插件进行初始化配置,启动各依赖组件处理器。下面来列举一下主要插件内容:
wallet_plugin,钱包管理相关,启动阶段只出现过一次,说明它的功能主要依赖启动后的操作,而在启动期间需要做的配置很少。
wallet_api_plugin,依赖于wallet_plugin,出现一次,应该是提供外部调用与钱包交互的接口服务。
http_plugin,启动阶段大量出现的插件,说明在准备期,针对HTTP的配置和添加接口服务非常多。配置包括url,端口,监听。接口服务包括钱包相关,链相关,账户相关的一系列api地址。
chain_plugin,链插件配置,出现了几次,除了初始化启动以外,还有针对链数据读取模式的配置为read/write模式,生成创世块配置文件genesis.json,以及展示了创世区块的各种属性信息。
chain_api_plugin,同样的,依赖于chain_plugin,提供外部调用链相关操作的接口服务。
net_plugin,网络插件,出现了几次,是对网络节点的基本配置,包括网络日志的级别为info,本地网络监听端口,生成节点id。最后启动监听器,并设置了以该网络节点为服务器的客户端最多能够连入25个。
main,主插件,对eosio这整个软件的一个主要插件,配置了eosio的版本以及展示了eosio工作的本地root地址。
account_history_api_plugin,顾名思义,账户历史接口插件,估计是与账户历史相关的供外部调用的接口服务。
producer_plugin,区块生产者插件,插件启动。
以上出现的所有插件亦可理解为组件。
接下来就是正常出块了,由于我们本地启动的节点一定是具备出块权的(目前只有一个节点未涉及共识),这些块是不包含任何交易信息的,出块速度很快。
停止
断开私链直接按下复制键(Ctrl+C)即可,日志中也有体现:
3571259ms thread-0 net_plugin.cpp:2954 plugin_shutdown ] shutdown..
3571259ms thread-0 net_plugin.cpp:2957 plugin_shutdown ] close acceptor
3571259ms thread-0 net_plugin.cpp:2960 plugin_shutdown ] close 0 connections
3571259ms thread-0 net_plugin.cpp:2968 plugin_shutdown ] exit shutdown
3571259ms thread-0 fork_database.cpp:94 close ] states.size(): 2
3571260ms thread-0 controller.cpp:218 ~controller_impl ] db.revision(): 37 head->block_num: 37 blog.read_head()->block_num(): 36
可以看到私链停止时,都是通过net_plugin插件来操作,操作的方法是与plugin_startup对应的plugin_shutdown,步骤为:
开始关闭的标识
关闭接收器acceptor
关闭连接
完成私链停止工作,退出shutdown程序
配置
EOS环境启动以后,可以在本地目录:~/.local/share/eosio/nodeos/ 找到链相关文件:
.
├── config
│ ├── config.ini
│ ├── config.ini.bak
│ ├── genesis.json
│ └── genesis.json.bak
└── data
├── blocks
│ ├── blocks.index
│ ├── blocks.log
│ └── unconfirmed
│ ├── shared_memory.bin
│ └── shared_memory.meta
└── shared_mem
├── forkdb.dat
├── shared_memory.bin
└── shared_memory.meta
5 directories, 11 files
根目录下包含config和data两个目录,data目录中存储了区块运行时数据,日志以及共享内存相关数据,我们重点来看config文件夹中的内容:
genesis.json
{
"initial_timestamp": "2018-03-01T12:00:00.000",
"initial_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"initial_configuration": {
"base_per_transaction_net_usage": 100,
"base_per_transaction_cpu_usage": 500,
"base_per_action_cpu_usage": 1000,
"base_setcode_cpu_usage": 2097152,
"per_signature_cpu_usage": 100000,
"per_lock_net_usage": 32,
"context_free_discount_cpu_usage_num": 20,
"context_free_discount_cpu_usage_den": 100,
"max_transaction_cpu_usage": 10485760,
"max_transaction_net_usage": 104857,
"max_block_cpu_usage": 104857600,
"target_block_cpu_usage_pct": 1000,
"max_block_net_usage": 1048576,
"target_block_net_usage_pct": 1000,
"max_transaction_lifetime": 3600,
"max_transaction_exec_time": 0,
"max_authority_depth": 6,
"max_inline_depth": 4,
"max_inline_action_size": 4096,
"max_generated_transaction_count": 16
},
"initial_chain_id": "0000000000000000000000000000000000000000000000000000000000000000"
}
可以看到初始化时间戳,初始化key,以及初始链id,链配置。其中链配置又包含了基础每笔交易的网络使用size、cpu使用size,每个方法、每个setcode、每个签名的cpu使用size,每个锁的网络使用size,空闲期间的cpu使用度折扣上下文,交易的cpu、网络使用度的最大值,区块的最大网络使用size,目标区块的网络使用size,交易最大存活生命周期长度、执行时间,权限深度的最大值,最大内联深度,最大内联操作size,交易的最大生成数量。
上面对genesis.json创世块描述文件进行了平铺直叙,我们可以看到,链时间,链key,链id都比较常见,而细致入微到标识了每个方法、每个签名等等的资源分配,这是很令人惊奇的。说明了
EOS对资源的控制是非常看中的。
config.ini
这是一个全局配置文件,就像java的property文件一样。这里面的配置会被细分到是由哪一个插件来使用的,例如针对http_plugin配置的地址端口号等等,我们也可以通过手动修改这些配置来控制链的一些表现。config.ini这个全局配置文件就是开放给外部人员,作为各种功能的静态变量配置,功能开关等工具使用。下面针对配置项逐一分析:
属于account_history_plugin插件的配置
filter_on_accounts:功能是实现仅追踪配置值的账户产生的交易,默认注释掉该配置项,意思是不设过滤器,追踪所有交易。
get-transactions-time-limit:执行单个get_transactions调用的执行时间,单位是豪妙,默认值为3(意思是3毫秒读不到就丢弃)
属于chain_plugin插件的配置
genesis-json,指定创世块配置文件位置,默认值是“genesis.json”
genesis-timestamp,复写初始化创世块时间戳,我们上面不是在启动命令中通过加入--genesis-timestamp参数来配置该值了么,在这里配置以后重启会是相同的效果。默认值是注释掉,启动时时间戳一般会过时。
block-log-dir:是区块日志的存储位置,绝对路径或者应用程序的相对路径。
checkpoint:是一对区块高度+区块id,用来作为检查点。默认注释掉,不设置检查点。(检查点的使用会在之后介绍,TODO)
max-reversible-block-time:允许可逆区块在被确认为无效之前存在的时间,默认为-1,不允许出现可逆区块。
max-pending-transaction-time:允许pending交易在无效之前的执行时间,默认为-1,不允许出现pending的交易。
max-defered-transaction-time:允许延迟执行交易到区块的推送时间,默认值20,
wasm-runtime:复写默认的WebAssembly的runtime。默认是注释掉(TODO:啥意思)
属于faucet_testnet_plugin配置
faucet-create-interval-ms:创建账户的间隔,默认1秒钟。
faucet-name:创建账户的创建器的名字。默认就是faucet。
faucet-private-key:公钥,WIF(TODO:解释WIF)私钥,用于faucet创建账户签名。默认值是在源码下载时指定的,我们可以通过工具自己更改。
属于http_plugin配置
http-server-address:本地IP端口,用于监听进入的http连接。默认值为127.0.0.1:8888
access-control-allow-origin:允许访问控制,每个请求会返回一个确定的access-control-allow-origin。默认注释掉,不设置特殊访问限制。
access-control-allow-headers:同上,只是不是http请求的origin控制了,而是通过http头来控制。默认也注释掉,不设置特殊访问限制。
access-control-allow-credentials:如果有特殊的访问限制证书则返回true。默认值为flase,不设限。
属于mongo_db_plugin配置
mongodb-queue-size:nodeos和mongodb组件线程之间的队列大小。默认值为256。
mongodb-uri:MongoDB的uri连接字符串,如果不配置则该mongodb组件是未被激活的,而使用默认的‘EOS’数据库。默认值不配置。
属于net_plugin配置
p2p-listen-endpoint:实际的主机加端口,用来监听进来的p2p连接。默认值为0.0.0.0:9876
p2p-server-address:一个外部访问的主机加端口,用于标识当前节点。默认使用上面的p2p-listen-endpoint配置。
p2p-peer-address:公共的对等节点的端点位置,提供外部连接。使用多重p2p-peer-address选项作为构成网络的需要。默认值是注释掉,不设置p2p相关配置。(TODO,p2p网络设置测试)
agent-name:在对等节点之间,用于标识一个节点而设置的名字。
allowed-connection:连接许可,可选值包括
any:允许所有连接,不设限制。
producers:仅允许区块生产者连接,节点key是不需要的。
specified:配置节点key作为特殊连接,可以与producers节点key重复(要配置多个的时候可以不适用producers,而用这个,否则没意义)
none:谁都不允许连入。
peer-key:可选项,允许连接的节点公钥。可以被多次使用。默认值是注释掉,不使用该配置项。
peer-private-key:公钥,WIF私钥元组,可被指定多次。默认注释掉,不使用。
log-level-net-plugin:日志级别包括all,debug,info,warn,error,off,这个不说了
max-clients:接收连接的客户端的最大数量,设为0的话表示没有限制。默认25个。
connection-cleanup-period:在清理死连接之前,等待的秒数。默认值是30s。
network-version-match:准确匹配对等网络版本。
sync-fetch-span:同步获取量,同步时,从任何个人节点取回作为一个chunk(大块)的区块数量,默认是100个。
属于producer_plugin配置
enable-stale-production:陈旧生产能力。即使链是陈旧的,也能够出块。默认值是false,不允许陈旧链(TODO:什么是陈旧链)
required-participation:必须参与出块。必须参与按序出块的区块生产者的百分比。默认值是33。至少33%的区块生产者是要参与到按序出块的。
producer-name:producer的ID,受节点控制。可能多次指定。默认值是注释掉,不使用。
private-key:私钥,公钥,WIF私钥元组,可以指定多次。默认值已有,可以修改。
属于wallet_plugin配置
wallet-dir:钱包文件的路径,绝对路径或者应用程序的相对路径。默认值是当前路径“.”
unlock-timeout:解锁钱包的超时时间,单位是秒。钱包在没有活动一段时间以后会自动上锁,这些活动可来自于任何钱包命令,例如list-wallet等。默认是注释掉,没有超时时间,不自动上锁。
eosio-key:在钱包创建时,eosio秘钥将被自动导入,默认是注释掉,先不设置,因为我吗是新创建钱包,未通过现有钱包导入。
plugin:激活插件,可以被特殊指定多次。默认是注释掉,没有特例,是插件都好使。
配置中出现的所有time的单位一般都是毫秒。
启动命令参数
配置文件加启动命令
上面我们通过命令
./nodeos -e -p eosio --genesis-timestamp2018-04-13T12:00:00.000--plugineosio::wallet_api_plugin --plugineosio::chain_api_plugin --plugineosio::account_history_api_plugin
启动了本地EOS环境。下面我们针对这个启动脚本的使用参数进行学习:
-e:enable-stale-production,参加上面config.ini的相关说明。设置以后相当于true。
-p:producer-name,给定了一个名字“eosio”用于出块者名字。
--plugin:就是config.ini最后一个配置字段。
所以我在config.ini针对以上命令进行静态配置。
enable-stale-production=trueproducer-name= eosio
plugin的配置方式:
# Load the block producer plugin, so you can produce blocks
plugin = eosio::producer_plugin
# Wallet plugin
plugin = eosio::wallet_api_plugin
# As well as API and HTTP plugins
plugin = eosio::chain_api_plugin
plugin = eosio::http_plugin
# This will be used by the validation step below, to view account history
plugin = eosio::account_history_api_plugin
配置结束以后,由于上面我们也执行了命令安装(sudo make install),下面我们可以直接在任何位置使用命令
nodeos
即可启动与之前命令相同的EOS本地环境。
指定配置文件地址
我们可以在机器中维护多套config.ini 以及 genesis.json文件,然后启动EOS环境时通过参数
--config-dir:指定地址用来加载配置文件,绝对路径或应用程序相对路径。
指定运行时数据地址
我们也可以通过启动参数指定运行时数据的存储位置。
--data-dir:指定地址用来存放运行时数据,日志以及共享内存相关数据,绝对路径或应用程序相对路径。
其实config-dir和data-dir就是映射的上面的~/.local/share/eosio/nodeos/的内容,我在上面使用树形结构列举了出来,他们通过启动参数均可指定新的位置。