小坚的技术博客

Ubuntu下EOS测试环境(私有链)搭建

本文作者:陈进坚
个人博客:https://jian1098.github.io
CSDN博客:https://blog.csdn.net/c_jian
简书:https://www.jianshu.com/u/8ba9ac5706b6
联系方式:jian1098@qq.com

环境要求

  • Ubuntu 16.04及以上
  • 内存4G以上(官方要求8G,可以通过修改文件降低要求)

编译安装

clone源码

1
root@iZj6c4i3ovav4gk164bft3Z:~# git clone https://github.com/eosio/eos.git --recursive

如果要编译指定版本,可以加上参数,例如:

1
git clone -b release/1.7.x https://github.com/eosio/eos.git --recursive

需要注意的是,MongoDB是EOS的依赖项之一,而在墙内下载该依赖项会失败,请先科学上网,再开始编译,否则会无法下载MongoDB导致编译失败。

编译

1
2
root@iZj6c4i3ovav4gk164bft3Z:~# cd eos/scripts
root@iZj6c4i3ovav4gk164bft3Z:~/eos/scripts$ sudo ./eosio_build.sh #需要3个小时左右,遇到错误请往下看

如果提示下面的信息,说明内存达不到要求,至少需要7G以上内存空间

1
2
3
......
Your system must have 7 or more Gigabytes of physical memory installed.
Exiting now.

将VMware的内存增加到4G多一点,记住要多一点,然后修改./scripts/eosio_build_ubuntu.sh文件,查找报错的那行代码

1
[[ $MEM_GIG -lt 7 ]] && echo "Your system must have 7 or more Gigabytes of physical memory installed." && exit 1

将7修改为4即可,意思是将配置要求降低到4G内存

如果看到下面的5个红色大字表示已经编译完成了,除开填坑的时间花了整整4个小时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[100%] Built target print_floats


_______ _______ _______ _________ _______
( ____ \( ___ )( ____ \\__ __/( ___ )
| ( \/| ( ) || ( \/ ) ( | ( ) |
| (__ | | | || (_____ | | | | | |
| __) | | | |(_____ ) | | | | | |
| ( | | | | ) | | | | | | |
| (____/\| (___) |/\____) |___) (___| (___) |
(_______/(_______)\_______)\_______/(_______)

EOSIO has been successfully built. 00:38:51

To verify your installation run the following commands:

export PATH=${HOME}/opt/mongodb/bin:$PATH
/home/jian/opt/mongodb/bin/mongod -f /home/jian/opt/mongodb/mongod.conf &
cd /home/jian/eos/build; make test

For more information:
EOSIO website: https://eos.io
EOSIO Telegram channel @ https://t.me/EOSProject
EOSIO resources: https://eos.io/resources/
EOSIO Stack Exchange: https://eosio.stackexchange.com
EOSIO wiki: https://github.com/EOSIO/eos/wiki

编译完成后安装、设置软连接

1
2
3
4
5
root@iZj6c4i3ovav4gk164bft3Z:~/eos# cd build
root@iZj6c4i3ovav4gk164bft3Z:~/eos/build$ sudo make install
root@iZj6c4i3ovav4gk164bft3Z:~/eos/build$ ln -fs /root/eos/build/bin/nodeos /usr/local/bin/nodeos
root@iZj6c4i3ovav4gk164bft3Z:~/eos/build$ ln -fs /root/eos/build/bin/keosd /usr/local/bin/keosd
root@iZj6c4i3ovav4gk164bft3Z:~/eos/build$ ln -fs /root/eos/build/bin/cleos /usr/local/bin/cleos

在./programs这个文件夹中可以找到eos的几个核心程序

  • nodeos: 区块链服务器节点生成组件。nedeos的配置文件位于~/Library/Application Support/eosio/nodeos/config文件夹中,区块数据存储在文件~/Library/Application Support/eosio/nodeos/data
  • cleos: 和区块链交互的接口命令,要指定服务器地址和端口请使用参数-u http://127.0.0.1:8888
  • keosd: EOS 钱包,作用是存储私钥,以便cleos用以签署交易并发送到区块链中。keosd在本机运行,并且将私钥存储在本地。keosd会随着cleos自动启动。
  • eosio-launcher:节点网络组成和部署的应用

配置文件

修改配置文件

1
2
root@iZj6c4i3ovav4gk164bft3Z:~# cd ~/.local/share/eosio/nodeos/config
root@iZj6c4i3ovav4gk164bft3Z:~/eos# vi config.ini

将下面的内容添加到配置文件的最后保存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# The local IP and port to listen for incoming http connections;
http-server-address = 127.0.0.1:8888

enable-stale-production = true
filter-on = *
producer-name = eosio
access-control-allow-origin = "*"
max-transaction-time=1000

# Load the block producer plugin, so you can produce blocks
plugin = eosio::producer_plugin

# As well as API and HTTP plugins
plugin = eosio::chain_api_plugin
plugin = eosio::http_plugin
http-validate-host = false

# This will be used by the validation step below, to view history
plugin = eosio::history_api_plugin
plugin = eosio::bnet_plugin
plugin = eosio::state_history_plugin

启动节点

1
root@iZj6c4i3ovav4gk164bft3Z:~/eos# nodeos -e -p eosio -d /root/eos/data --contracts-console --trace-history --verbose-http-errors --disable-replay-opts

参数说明:

-p:表示使用了 本地测试系统提供的原始账户 eosio 账户的权限

-d:区块数据存放目录

–plugin:插件

-e:开启Stale Production,即即便当前时间已经超过规定的区块生产时限,也继续产生

–plugin eosio::chain_api_plugin:开启区块链JSON API插件。

–plugin eosio::history_api_plugin:开启历史数据插件,有了这个插件,便能查询许多不在State中的数据,譬如一个公钥所对应的所有账户等等。

–contracts-console:开启合约控制台。如果不开启的话,合约中调用print函数输出的信息将会不可见。

–filter-on “*”:开启所有账户的历史纪录。默认状态下,节点不会记录账户的历史数据,从而使得命令cleos get actions返回空。

–access-control-allow-origin “*”:允许任意域名跨域访问API,如果不开启,在dApp开发中,网站会报错。

  • 如果启动节点报错database dirty flag set (likely due to unclean shutdown): replay required,说明节点非正常退出导致数据异常,需要在启动命令加上参数--hard-replay

停止节点

按下Ctrl+C即可停止节点

创建脚本

由于启动命令太长不方便记忆,我们需要写一个启动脚本方便启动和停止,并且在后台运行程序

1
vi start_nodeos.sh

将下面的内容复制进去保存,启动命令根据自己的需求修改

1
2
3
#!/bin/bash

nohup nodeos -e -p eosio -d /root/eos/data --contracts-console --trace-history --verbose-http-errors --disable-replay-opt >> nodeos.log 2>&1 &

然后制作停止脚本

1
vi stop_nodeos.sh

将下面的内容复制进去保存

1
2
3
4
5
6
7
8
#!/bin/bash

PIDS=`ps -ef |grep nodeos |grep -v grep | awk '{print $2}'`
if [ "$PIDS" != "" ]; then
kill -9 $PIDS
else
echo `date +%F" "%H:%M:%S` "nodeos is NOT runing!"
fi

配置脚本执行权限

1
chmod u+x st*.sh

查看权限

1
ls -la *.sh

后台要启动nodeos程序只要执行./start_nodeos.sh即可,查看日志文件

1
tail -f nodeos.log

导入私钥

首先我们需要创建一个默认的钱包,请记住的到的私钥

1
2
3
4
5
6
7
root@iZj6c4i3ovav4gk164bft3Z:~/eos# cleos wallet create --to-console

"/root/eos/build/bin/keosd" launched
Creating wallet: default
Save password to use in the future to unlock this wallet.
Without password imported keys will not be retrievable.
"PW5JpwC9Xbakce63ZEFRpqh2LEFSRwdXhrCDo67L86gKnxYPJihZA"

这里创建了钱包名为default,密码为PW5JpwC9Xbakce63ZEFRpqh2LEFSRwdXhrCDo67L86gKnxYPJihZA的钱包。

进入配置文件

1
2
root@iZj6c4i3ovav4gk164bft3Z:~/eos/build/programs/cleos$ cd ~/.local/share/eosio/nodeos/config
root@iZj6c4i3ovav4gk164bft3Z:~/.local/share/eosio/nodeos/config# vi config.ini

找到这一行

1
# signature-provider = EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV=KEY:5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3

这是指定了默认区块产生者eosio的公私钥对,其中公钥为:EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV

相对应的私钥为:5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3

为什么钱包中已经有密钥对了还要再添加?

每个EOS帐户都拥有owner(所有者)和active(活动权限)两个权限,因此,在大多数情况下,需要创建两个密钥,以便可以将一个密钥与每个权限相关联。

首先创建两个密钥对

1
2
3
4
5
6
7
8
root@iZj6c4i3ovav4gk164bft3Z:~/eos# cd ~/eos/build/programs/cleos
root@iZj6c4i3ovav4gk164bft3Z:~/eos/build/programs/cleos$ sudo ./cleos create key --to-console
Private key: 5JxhYZZnFJJMRrf7KkSHNLFq2LM4eZigJfeKXXYSa1TvPMdWtLc
Public key: EOS5Fwtc4vnQE8AigimXvHrERrK7XFpycQ8Dijq2611timbVTReDt

root@iZj6c4i3ovav4gk164bft3Z:~/eos/build/programs/cleos$ sudo ./cleos create key --to-console
Private key: 5JXNT5zRfFDwzc7mKmd3AiYjT9dvfDosiFAo1drkneY6TrhTRUp
Public key: EOS75hPAeMGgAw9FYLTAHqjHyicjW82bB1q9grXqDtCdMDMpe1eoa

然后依次将eosio的私钥和两个Private key导入到创建的默认钱包中

1
2
3
4
5
6
7
8
root@iZj6c4i3ovav4gk164bft3Z:~/.local/share/eosio/nodeos/config# cleos wallet import --private-key 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3
imported private key for: EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV

root@iZj6c4i3ovav4gk164bft3Z:~/.local/share/eosio/nodeos/config# cleos wallet import --private-key 5JxhYZZnFJJMRrf7KkSHNLFq2LM4eZigJfeKXXYSa1TvPMdWtLc
imported private key for: EOS5Fwtc4vnQE8AigimXvHrERrK7XFpycQ8Dijq2611timbVTReDt

root@iZj6c4i3ovav4gk164bft3Z:~/.local/share/eosio/nodeos/config# cleos wallet import --private-key 5JXNT5zRfFDwzc7mKmd3AiYjT9dvfDosiFAo1drkneY6TrhTRUp
imported private key for: EOS75hPAeMGgAw9FYLTAHqjHyicjW82bB1q9grXqDtCdMDMpe1eoa

可以看到导入私钥后会自动给出对应的公钥。

在次打开默认钱包可以看到默认钱包中已经有3个密钥对了

1
2
3
4
5
6
root@iZj6c4i3ovav4gk164bft3Z:~/.local/share/eosio/nodeos/config# cleos wallet keys
[
"EOS5Fwtc4vnQE8AigimXvHrERrK7XFpycQ8Dijq2611timbVTReDt",
"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"EOS75hPAeMGgAw9FYLTAHqjHyicjW82bB1q9grXqDtCdMDMpe1eoa"
]

发行代币

在部署eosio.EOStem合约之前,必须先创建如下账户,创建账号使用eosio的公私钥对:

1
2
3
4
5
6
7
8
9
10
11
EOStemAccounts = [
'eosio.bpay',
'eosio.msig',
'eosio.names',
'eosio.ram',
'eosio.ramfee',
'eosio.saving',
'eosio.stake',
'eosio.token',
'eosio.upay',
]

创建命令如下:

1
2
3
4
5
6
7
8
9
cleos create account eosio eosio.bpay EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV;
cleos create account eosio eosio.msig EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV;
cleos create account eosio eosio.names EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV;
cleos create account eosio eosio.ram EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV;
cleos create account eosio eosio.ramfee EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV;
cleos create account eosio eosio.saving EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV;
cleos create account eosio eosio.stake EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV;
cleos create account eosio eosio.token EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV;
cleos create account eosio eosio.upay EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV;

执行的结果如下:

1
2
3
4
executed transaction: 9da6a67895e9efc1a794e4beae1f8134e6a3a0e866a5092cdfb55f77b7642c5d  200 bytes  192 us
# eosio <= eosio::newaccount {"creator":"eosio","name":"eosio.upay","owner":{"threshold":1,"keys":[{"key":"EOS6MRyAjQq8ud7hVNYcfn...
warn 2018-11-28T03:33:33.304 thread-0 main.cpp:482 print_resuwarning: transaction executed locally, but may not be confirmed by the network yet
......

接下来将代币合约部署到eosio.token账户中:

1
2
3
4
5
6
7
8
9
10
11
12
root@iZj6c4i3ovav4gk164bft3Z:~/eos/build/programs/cleos$ cd /root/eos/build/unittests/contracts  # 进入编译后的合约目录

root@iZj6c4i3ovav4gk164bft3Z:~/eos/build/unittests/contracts# cleos set contract eosio.token ./eosio.token


#执行结果:
Reading WASM from ./eosio.token/eosio.token.wasm...
Publishing contract...
executed transaction: 69b358aab5d199797aa8165b5969646881aed401ea03b2b6def43affdd183f3e 8104 bytes 27919 us
# eosio <= eosio::setcode {"account":"eosio.token","vmtype":0,"vmversion":0,"code":"0061736d01000000017e1560037f7e7f0060057f7e...
# eosio <= eosio::setabi {"account":"eosio.token","abi":"0e656f73696f3a3a6162692f312e30010c6163636f756e745f6e616d65046e616d65...
warn 2018-11-28T03:41:50.674 thread-0 main.cpp:482 print_resuwarning: transaction executed locally, but may not be confirmed by the network yet

创建1亿个EOS代币(这里的EOS币相当于主网中的EOS):

1
2
3
4
5
6
root@iZj6c4i3ovav4gk164bft3Z:~/eos/build/unittests/contracts# cleos push action eosio.token create '["eosio","10000000000.0000 EOS",0,0,0]' -p eosio.token

#执行结果:
executed transaction: cb0973dfa4a52dd0c99ef56834c84d391dda565a4aeeafaaafaef5642190f4e4 120 bytes 1436 us
# eosio.token <= eosio.token::create {"issuer":"eosio","maximum_supply":"100000000.0000 EOS"}
warn 2018-11-28T03:44:50.857 thread-0 main.cpp:482 print_resuwarning: transaction executed locally, but may not be confirmed by the network yet

发行代币,数量:10000000000,代币符号:EOS。

1
2
3
4
5
6
root@iZj6c4i3ovav4gk164bft3Z:~/eos/build/unittests/contracts# cleos push action eosio.token issue '["eosio","10000000000.0000 EOS","issue"]' -p eosio

# 执行结果
executed transaction: 59f8a3fe587335f5c3ebdd12ac7a39f638cf028966a6efa2250f1244e82f178d 128 bytes 1288 us
# eosio.token <= eosio.token::issue {"to":"eosio","quantity":"10000000000.0000 EOS","memo":"memo"}
warn 2018-11-28T03:54:16.092 thread-0 main.cpp:482 print_resuwarning: transaction executed locally, but may not be confirmed by the network yet

查询余额

1
2
3
root@iZj6c4i3ovav4gk164bft3Z:~/eos/build/unittests/contracts# cleos get currency balance eosio.token eosio

10000000000.0000 EOS

创建账号

在EOS中,为了控制权限,创建账号是需要指定一个创建者的,例如默认钱包的创建者是eosio,所以创建default账号中含有eosio的私钥。

创建账户的格式如下:

1
cleos create account AUTHORIZING_ACCOUNT NEW_ACCOUNT OWNER_KEY ACTIVE_KEY
  • authorizing_account 是新账户的创建者。在此教程中,由于我们运行的是一个单节点测试网络,所以我们拥有一个名为eosio的系统账户,因此我们使用eosio作为新账户的创建者

  • new_account 是要创建的账户名称

  • owner_key 是账户owner权限的公钥

  • active_key 是账户active权限的公钥

我们使用account1作为新账户名称,使用eosio作为新账户的创建者,使用之前生成并导入default钱包的两个公钥EOS5Fwtc4vnQE8AigimXvHrERrK7XFpycQ8Dijq2611timbVTReDtEOS75hPAeMGgAw9FYLTAHqjHyicjW82bB1q9grXqDtCdMDMpe1eoa分别作为owner权限和active权限的公钥,注意这里是使用公钥!!!

1
root@iZj6c4i3ovav4gk164bft3Z:~/eos/build/unittests/contracts# cleos create account eosio account1 EOS5Fwtc4vnQE8AigimXvHrERrK7XFpycQ8Dijq2611timbVTReDt EOS75hPAeMGgAw9FYLTAHqjHyicjW82bB1q9grXqDtCdMDMpe1eoa

我这里报错了,因为交易是需要RAM资源的。如果没有报错请忽略下面一步。

1
2
3
Error 3080001: Account using more than allotted RAM usage
Error Details:
account account1 has insufficient ram; needs 2996 bytes has 0 bytes

将创建命令改为下面的才能成功

1
2
3
4
5
6
7
8
9
10
11
12
13
root@iZj6c4i3ovav4gk164bft3Z:~/eos/build/programs/cleos$ sudo ./cleos  system newaccount eosio account1 EOS5Fwtc4vnQE8AigimXvHrERrK7XFpycQ8Dijq2611timbVTReDt EOS75hPAeMGgAw9FYLTAHqjHyicjW82bB1q9grXqDtCdMDMpe1eoa --stake-net '0 EOS' --stake-cpu '0 EOS' --buy-ram-kbytes 3 -x 30


executed transaction: 5171d92b16934b8a773a57e617aba5443f5394551cba376eb2d61788ea7460b4 248 bytes 1448 us
# eosio <= eosio::newaccount {"creator":"eosio","name":"account1","owner":{"threshold":1,"keys":[{"key":"EOS5Fwtc4vnQE8AigimXvHrE...
# eosio <= eosio::buyrambytes {"payer":"eosio","receiver":"account1","bytes":3072}
# eosio.token <= eosio.token::transfer {"from":"eosio","to":"eosio.ram","quantity":"0.4447 SYS","memo":"buy ram"}
# eosio <= eosio.token::transfer {"from":"eosio","to":"eosio.ram","quantity":"0.4447 SYS","memo":"buy ram"}
# eosio.ram <= eosio.token::transfer {"from":"eosio","to":"eosio.ram","quantity":"0.4447 SYS","memo":"buy ram"}
# eosio.token <= eosio.token::transfer {"from":"eosio","to":"eosio.ramfee","quantity":"0.0023 SYS","memo":"ram fee"}
# eosio <= eosio.token::transfer {"from":"eosio","to":"eosio.ramfee","quantity":"0.0023 SYS","memo":"ram fee"}
# eosio.ramfee <= eosio.token::transfer {"from":"eosio","to":"eosio.ramfee","quantity":"0.0023 SYS","memo":"ram fee"}
warn 2018-12-05T10:49:19.302 thread-0 main.cpp:482 print_resuwarning: transaction executed locally, but may not be confirmed by the network yet

查询刚刚创建的账号:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
root@iZj6c4i3ovav4gk164bft3Z:~/eos/build/unittests/contracts# cleos get account account1

created: 2018-12-05T10:49:19.500
permissions:
owner 1: 1 EOS5Fwtc4vnQE8AigimXvHrERrK7XFpycQ8Dijq2611timbVTReDt
active 1: 1 EOS75hPAeMGgAw9FYLTAHqjHyicjW82bB1q9grXqDtCdMDMpe1eoa
memory:
quota: 2.982 KiB used: 2.926 KiB

net bandwidth:
delegated: 0.0000 SYS (total staked delegated to account from others)
used: 0 bytes
available: 0 bytes
limit: 0 bytes

cpu bandwidth:
delegated: 0.0000 SYS (total staked delegated to account from others)
used: 0 us
available: 0 us
limit: 0 us

锁定钱包

锁定默认钱包

1
2
root@iZj6c4i3ovav4gk164bft3Z:~/eos# cleos wallet lock
Locked: default

锁定指定钱包

1
2
3

root@iZj6c4i3ovav4gk164bft3Z:~/eos# cleos wallet lock -n accountname
Locked: accountname

keosd会在没有钱包指令的15分钟后自动锁定钱包,可以在~/eosio-wallet/config.ini中进行时长修改。可以设置一个超大数来取消这项功能。如果设为0,将会导致钱包永久锁定。

解锁钱包

没有-n指定钱包名会解锁默认钱包,默认钱包解锁密码是”导入私钥”中创建钱包时得到的PW开头的私钥

1
2
root@iZj6c4i3ovav4gk164bft3Z:~/eos# cleos wallet unlock -n accountname
password: Unlocked: accountname

再次查看钱包,可以看到有*号表示已经解锁了

1
2
3
4
5
root@iZj6c4i3ovav4gk164bft3Z:~/eos# cleos wallet list
Wallets:
[
"default"
]

发送交易

转100个币到account1账号中

1
root@iZj6c4i3ovav4gk164bft3Z:~/eos# cleos push action eosio.token transfer '["eosio", "account1","100.0000 EOS","memo"]' -p eosio

查询account1账号的余额

1
2
root@iZj6c4i3ovav4gk164bft3Z:~/eos# cleos get currency balance eosio.token account1
100.0000 EOS

参考文章

RPC中文文档:http://cw.hubwiz.com/card/c/eos-rpc-api

EOS WiKi中文版https://eoswiki.readthedocs.io/zh_CN/latest/

https://www.jianshu.com/nb/24907261

https://zhuanlan.zhihu.com/p/40009564

https://blog.csdn.net/littlefool5201314/article/details/79869114

https://www.jianshu.com/p/13c7bddacfd9

https://www.bcskill.com/index.php/archives/21.html

-------------本文结束感谢您的阅读-------------
🐶 您的支持将鼓励我继续创作 🐶