本文我们尝试使用docker搭建 eos2.0.* 测试网络,通过区块链网络练习如何编译和运行EOS智能合约,并测试交易。

EOS核心组件

EOS区块链开发主要应用到以下的组件:

  • nodeos:块生成器守护程序。
  • keosd:钱包守护进程,存储私钥。
  • eosio-cpp:智能合约编译器。
  • eosio.token:平台的参考标记。
  • cleos:用于与EOS区块链远程交互的CLI。
  • scatter:为本地Testnet配置的EOS钱包。

测试网络运行环境

  • Ubuntu Linux
  • docker/docker-compose

创建docker和docker-compose

dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
FROM ubuntu:18.04

RUN apt-get update && apt-get install -y curl wget libicu60 libusb-1.0-0 libcurl3-gnutls
#######

#区块链
RUN wget https://github.com/eosio/eos/releases/download/v2.0.3/eosio_2.0.3-1-ubuntu-18.04_amd64.deb
RUN apt install ./eosio_2.0.3-1-ubuntu-18.04_amd64.deb

#合约开发工具
RUN wget https://github.com/EOSIO/eosio.cdt/releases/download/v1.7.0/eosio.cdt_1.7.0-1-ubuntu-18.04_amd64.deb
RUN apt install ./eosio.cdt_1.7.0-1-ubuntu-18.04_amd64.deb


RUN wget https://github.com/EOSIO/eosio.cdt/archive/v1.7.0.tar.gz
RUN tar -xvzf v1.7.0.tar.gz --one-top-level=eosio.cdt --strip-components 1

RUN wget https://github.com/EOSIO/eosio.contracts/archive/v1.9.1.tar.gz
RUN tar -xvzf v1.9.1.tar.gz --one-top-level=eosio.contracts --strip-components 1

docker-compose.yml

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

version: '3'

services:
mongo-db:
image: mongo:latest
container_name: mongo-db
ports:
- 27017:27017
environment:
TZ: Asia/Shanghai
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: admin@123
volumes:
- /Users/zgq/docker/volumes/mongo/db:/data/db
logging:
driver: "json-file"
options:
max-size: "200k"
max-file: "10"

mongo-express:
image: mongo-express:latest
container_name: mongo-express
links:
- mongo-db:mongodb
depends_on:
- mongo-db
ports:
- 27018:8081
environment:
ME_CONFIG_OPTIONS_EDITORTHEME: 3024-night
ME_CONFIG_MONGODB_SERVER: mongodb
ME_CONFIG_MONGODB_ADMINUSERNAME: admin
ME_CONFIG_MONGODB_ADMINPASSWORD: admin@123
ME_CONFIG_BASICAUTH_USERNAME: admin
ME_CONFIG_BASICAUTH_PASSWORD: admin@123

keosd:
container_name: keosd
hostname: keosd
image: zgq/eos
command: keosd --http-server-address=0.0.0.0:8901 --http-validate-host 0 --verbose-http-errors --unlock-timeout=9999999
volumes:
- /Users/zgq/docker/volumes/eos/eosio-wallet:/root/eosio-wallet
expose:
- 8901
ports:
- '8901:8901'
nodeos:
container_name: nodeos
image: zgq/eos
command: nodeos -e -p eosio --plugin eosio::producer_plugin --plugin eosio::history_plugin --plugin eosio::chain_api_plugin --plugin eosio::history_api_plugin --plugin eosio::http_plugin --http-server-address=0.0.0.0:8888 --access-control-allow-origin=* --contracts-console --http-validate-host=false --filter-on="*"
stop_grace_period: 3m0s
volumes:
- /Users/zgq/docker/volumes/eos/contract:/eosio.contracts/contract
- /Users/zgq/docker/volumes/eos/config:/root/.local/share/eosio/nodeos/config
ports:
- '8888:8888'
- '9830:9876'
depends_on:
- keosd
- mongo-db

启动区块链

在宿主机终端运行

1
docker-compose up

可以看到运行结果

nodeos效果
可以看到网络正在生成区块

接着我们在宿主机执行以下命令查看区块链信息

1
2
3
alias cleos="docker exec -it nodeos cleos --url http://127.0.0.1:8888 --wallet-url http://keosd:8901"

cleos get info

cleos

我们可见此时的区块高度是1008

创建钱包、钥匙、房子(账户)

钱包就像是房东,房东可以有很多的房子和各种开门的钥匙。如果厦门市是一个区块链节点,厦门市有很多房东,因此所以一个节点可以创建多个钱包。
钥匙分为私钥和公钥,公钥是别人可以看到的,你拿到公钥也打不开房子。你得拿到钱包里的私钥才可以打开房子。房东可以把很多的房子配成一样的锁,用一对公钥/私钥来开门,也可以不同的房子不同的钥匙。
一个账户可以有两把钥匙对:owner和active。owner地址实际上对应了公钥,用它对应的私钥可以打开房子,这个钱包不能给账户主人之外的任何人;
active钥匙对为外人的钥匙对,表示外人可以使用active的私钥打开账户;

首先我们需要创建两对钥匙

1
cleos create key --to-console

结果如下:

1
2
3
4
5
6
7
8
#key1
cleos create key --to-console
Private key: 5KUUc1wsZuDiZSKjhVRH3iMz82A2bg58v2stzzyYzZWWeFhKp2H
Public key: EOS66dDgbVGgtvGJ4W42igj45od75Bmbj6P1hJtwm6gKb5WEKtU3a
#key2
cleos create key --to-console
Private key: 5J3CA2Y57zkU6U4UPWgKJfgwA4eMs7gvGrLz8nxk5U7xtpFXb9a
Public key: EOS6raVF1gmpf6y6Qpm2Gtmn3LZyXf69oHiiGtv421sb9b68cDpqG

默认情况下测试网络有一个账户eosio,他的密钥是
eosio public key: EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
eosio private key: 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3

接着我们创建一个钱包(默认钱包名是default)

1
2
3
4
5
6
7
8
cleos wallet create --to-console
```
反馈
```text
Creating wallet: default
Save password to use in the future to unlock this wallet.
Without password imported keys will not be retrievable.
"PW5HtRdnY9BtKPWWiYiE5xQfeMhtJxJjHzF8uAFv13u6WBiRiSDut"

接着将钥匙放到钱包里面

1
2
3
4
5
#导入eosio密钥
cleos wallet import --private-key 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3
#导入其他新创建的密钥
cleos wallet import --private-key 5KUUc1wsZuDiZSKjhVRH3iMz82A2bg58v2stzzyYzZWWeFhKp2H
cleos wallet import --private-key 5J3CA2Y57zkU6U4UPWgKJfgwA4eMs7gvGrLz8nxk5U7xtpFXb9a

查看钱包和钥匙

1
2
3
4

cleos wallet list

cleos wallet keys

接着我们创建eosio.token帐户

1
cleos create account eosio eosio.token EOS66dDgbVGgtvGJ4W42igj45od75Bmbj6P1hJtwm6gKb5WEKtU3a EOS6raVF1gmpf6y6Qpm2Gtmn3LZyXf69oHiiGtv421sb9b68cDpqG

出现错误

1
Error 3090003: provided keys, permissions, and delays do not satisfy declared authorizations

那是因为测试网络只能用这个账户:

eosio public key: EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
eosio private key: 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3

因此我们需要执行:

1
2

cleos wallet import --private-key 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3

再次创建账户

1
cleos create account eosio eosio.token EOS66dDgbVGgtvGJ4W42igj45od75Bmbj6P1hJtwm6gKb5WEKtU3a EOS6raVF1gmpf6y6Qpm2Gtmn3LZyXf69oHiiGtv421sb9b68cDpqG

执行成功提示信息:

1
2
3
executed transaction: 428069546e69d7dd6f3783f5ae4cc0777d7f50235c459c8272e18e93f7c9c0f0  200 bytes  13443 us
# eosio <= eosio::newaccount "0000000000ea305500a6823403ea3055010000000100029f406256fc1e646cce646ac2628ccf1380323a678baf49a26378a...
warning: transaction executed locally, but may not be confirmed by the network yet

部署智能合约(eosio.token)

首先我们编译智能合约

1
2

docker exec -it nodeos bash -c "cd /eosio.contracts/contracts/ && eosio-cpp -I eosio.token/include/ -abigen -o eosio.token/src/eosio.token.wasm eosio.token/src/eosio.token.cpp"

接着安装

1
2

cleos set contract eosio.token /eosio.contracts/contracts/eosio.token/src eosio.token.wasm eosio.token.abi -p eosio.token@active

执行成功提示:

1
2
3
4
5
6
7

Reading WASM from /eosio.contracts/contracts/eosio.token/src/eosio.token.wasm...
Publishing contract...
executed transaction: 83c00e45780cc0df88a8b2eb3bde16575a963f30754aeac59179eaae6d89070a 6984 bytes 18008 us
# eosio <= eosio::setcode {"account":"eosio.token","vmtype":0,"vmversion":0,"code":"0061736d0100000001a0011b60000060017e006002...
# eosio <= eosio::setabi {"account":"eosio.token","abi":"0e656f73696f3a3a6162692f312e310008076163636f756e7400010762616c616e63...
warning: transaction executed locally, but may not be confirmed by the network yet ]

创建2个测试账户

1
2
3
cleos create account eosio zgq EOS66dDgbVGgtvGJ4W42igj45od75Bmbj6P1hJtwm6gKb5WEKtU3a EOS6raVF1gmpf6y6Qpm2Gtmn3LZyXf69oHiiGtv421sb9b68cDpqG

cleos create account eosio zgq2 EOS66dDgbVGgtvGJ4W42igj45od75Bmbj6P1hJtwm6gKb5WEKtU3a EOS6raVF1gmpf6y6Qpm2Gtmn3LZyXf69oHiiGtv421sb9b68cDpqG

创建成功提示

1
2
3
4

executed transaction: d131dda4fb48281ffd5e16f45f9ca030a619e57aee7a1b69d345345106ce8158 200 bytes 626 us
# eosio <= eosio::newaccount {"creator":"eosio","name":"zgq","owner":{"threshold":1,"keys":[{"key":"EOS66dDgbVGgtvGJ4W42igj45od75...
warning: transaction executed locally, but may not be confirmed by the network yet ]

给eosio一些钱

1
2
3
cleos push action eosio.token create '[ "eosio", "1000000000.0000 EOS"]' -p eosio.token@active  

cleos push action eosio.token issue '["eosio", "1000000000.0000 EOS", "m"]' -p eosio

查看余额

1
2
cleos get currency balance eosio.token eosio
100000.0000 EOS

查看账户余额

1
cleos get currency balance eosio.token zgq

这个时候zgq的账户余额还是0

执行一笔交易,将从eosio转10000.0000到zgq账户,注意小数点个数要一致

1
cleos push action eosio.token transfer '["eosio","zgq","100.0000 EOS","BUY LAMBOOO!!!"]' -p eosio

查看账户余额

1
2
cleos get currency balance eosio.token zgq
10000.0000 EOS