Getting Started
本次体验依据EOSIO官方教程Getting Started章节
体验了启动节点、管理钱包、创建账户、编写合约、编译部署合约、调用合约等功能
详情参看https://developers.eos.io/welcome/latest/getting-started/index/
不足之处,欢迎指正。
EOS是什么?
- 软件:EOS可以理解为对eos.io软件的简称。eos.io软件由block.one公司开发,构建了EOS区块链的底层技术架构;eos.io类似于区块链中的操作系统,开发者可以基于此工具快速构建DAPP。
- 通证: EOS可以指是一种通证(token),目前可以支持在EOS、BOS中进行交换,具有一定的价值。
- 公链:EOS也可以理解为采用DPOS共识机制的一种底层公链架构,其采用投票机制选择21个节点为主节点完成交易的打包。
本文我们尝试的EOS是指软件eos.io
一 免安装体验版
如果觉得本地安装比较麻烦,可以直接访问:
https://gitpod.io/#https://github.com/EOSIO/eosio-web-ide
Tips:初次访问需要配置环境,打开页面可能会慢些。
想要了解更多Web IDE的细节,可以访问
https://github.com/EOSIO/eosio-web-ide
(1)编译合约
先看下合约文件talk.cpp
#include <eosio/eosio.hpp>
// Message table
struct [[eosio::table("message"), eosio::contract("talk")]] message {
uint64_t id = {
}; // Non-0
uint64_t reply_to = {
}; // Non-0 if this is a reply
eosio::name user = {
};
std::string content = {
};
uint64_t primary_key() const {
return id; }
uint64_t get_reply_to() const {
return reply_to; }
};
using message_table = eosio::multi_index<
"message"_n, message, eosio::indexed_by<"by.reply.to"_n, eosio::const_mem_fun<message, uint64_t, &message::get_reply_to>>>;
// The contract
class talk : eosio::contract {
public:
// Use contract's constructor
using contract::contract;
// Post a message
[[eosio::action]] void post(uint64_t id, uint64_t reply_to, eosio::name user, const std::string& content) {
message_table table{
get_self(), 0};
// Check user
require_auth(user);
// Check reply_to exists
if (reply_to)
table.get(reply_to);
// Create an ID if user didn't specify one
eosio::check(id < 1'000'000'000ull, "user-specified id is too big");
if (!id)
id = std::max(table.available_primary_key(), 1'000'000'000ull);
// Record the message
table.emplace(get_self(), [&](auto& message) {
message.id = id;
message.reply_to = reply_to;
message.user = user;
message.content = content;
});
}
};
在IDE中新建终端,运行
eosio-cpp contract/talk.dpp
完成合约的编译,会在contract文件目录生成talk.abi与talk.wasm
#talk.abi内容
{
"____comment": "This file was generated with eosio-abigen. DO NOT EDIT ",
"version": "eosio::abi/1.1",
"types": [],
"structs": [
{
"name": "message",
"base": "",
"fields": [
{
"name": "id",
"type": "uint64"
},
{
"name": "reply_to",
"type": "uint64"
},
{
"name": "user",
"type": "name"
},
{
"name": "content",
"type": "string"
}
]
},
{
"name": "post",
"base": "",
"fields": [
{
"name": "id",
"type": "uint64"
},
{
"name": "reply_to",
"type": "uint64"
},
{
"name": "user",
"type": "name"
},
{
"name": "content",
"type": "string"
}
]
}
],
"actions": [
{
"name": "post",
"type": "post",
"ricardian_contract": ""
}
],
"tables": [
{
"name": "message",
"type": "message",
"index_type": "i64",
"key_names": [],
"key_types": []
}
],
"ricardian_clauses": [],
"variants": []
talk.wasm为编译后的二进制文件,会在合约部署时分发至各节点。
(2)安装合约
cleos create account eosio talk EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
cleos set code talk talk.wasm
cleos set abi talk talk.abi
***命令执行后无反应,放弃了!***
开玩笑的,如遇到创建账号无反应,请重启一下工作空间。因为创建账号需要存调用系统合约,请注意不能关闭出块进程(下图页面):
输出如下:
$ cleos create account eosio talk EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
executed transaction: f08fb469311c57c280e6ebcc0f038572ed230e28c070d48a60711b4183aabb92 200 bytes 282 us
# eosio <= eosio::newaccount {"creator":"eosio","name":"talk","owner":{"threshold":1,"keys":[{"key":"EOS6MRyAjQq8ud7hVNYcfnVPJqcV...
warning: transaction executed locally, but may not be confirmed by the network yet ]
$ cleos set code talk talk.wasm
Reading WASM from /workspace/eosio-web-ide/contract/talk.wasm...
Setting Code...
executed transaction: 4afac605a367ccf58dcf093463e881221bf910b29ad65b6ece4dfc85d695cc80 4024 bytes 736 us
# eosio <= eosio::setcode {"account":"talk","vmtype":0,"vmversion":0,"code":"0061736d0100000001a2011a6000006000017f60027f7f006...
warn 2020-09-01T04:32:52.185 cleos main.cpp:495 warning: transaction executed locally, but may not be confirmed by the network yet
$ cleos set abi talk talk.abi
Setting ABI...
executed transaction: 941ddd90e63716f21f2568668dd967574b696b58c3ed189ede86b8e28d80da82 200 bytes 139 us
# eosio <= eosio::setabi {"account":"talk","abi":"0e656f73696f3a3a6162692f312e310002076d65737361676500040269640675696e7436340...
warn 2020-09-01T04:33:03.198 cleos main.cpp:495 warning: transaction executed locally, but may not be confirmed by the network yet
warn:原因是交易刚上传至链上,尚未被其他节点确认。
(3)创建用户并调用合约
#创建用户bob、alice
cleos create account eosio bob EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
cleos create account eosio jane EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
#调用talk合约中post动作
cleos push action talk post '[1000, 0, bob, "This is a new post"]' -p bob
cleos push action talk post '[2000, 0, jane, "This is my first post"]' -p jane
cleos push action talk post '[1001, 2000, bob, "Replying to your post"]' -p bob
(4)监听链上信息
cleos get table talk '' message
会反馈talk合约的链上信息:
{
"rows": [{
"id": 1000,
"reply_to": 0,
"user": "bob",
"content": "This is a new post"
},{
"id": 1001,
"reply_to": 2000,
"user": "bob",
"content": "Replying to your post"
},{
"id": 2000,
"reply_to": 0,
"user": "jane",
"content": "This is my first post"
}
],
"more": false
}
(5)前端页面展示
IDE中已经用React实现了数据展示功能,输入:
gp preview $(gp url 8000)
弹出前端页面效果如下:
(6)构建并运行单元测试
返回上层目录,在eosio-web-ide目录下运行:
./build-tests
该命令会调用test文件夹下的所有.cpp文件,进行构建(build)操作。过程大概需要40秒,耐心等待。
将contract目录下产生的talk.wasm、talk.abi文件复制(或者移动)到tester所在目录。
运行:
./tester
正常运行时,显示
***No errors detected
如果感兴趣可以查看下talk_tests.cpp,该文件一次性实现了合约加载,创建用户,调用action,异常处理;
#include <boost/test/unit_test.hpp>
#include <eosio/chain/abi_serializer.hpp>
#include <eosio/chain/permission_object.hpp>
#include <eosio/chain/resource_limits.hpp>
#include <eosio/testing/tester.hpp>
using namespace eosio;
using namespace eosio::chain;
using namespace eosio::testing;
using namespace fc;
BOOST_AUTO_TEST_SUITE(talk_tests)
BOOST_AUTO_TEST_CASE(post) try {
tester t{
setup_policy::none};
// Load contract
t.create_account(N(talk));
t.set_code(N(talk), read_wasm("talk.wasm"));
t.set_abi(N(talk), read_abi("talk.abi").data());
t.produce_block();
// Create users
t.create_account(N(john));
t.create_account(N(jane));
// Test "post" action
t.push_action(
N(talk), N(post), N(john),
mutable_variant_object //
("id", 1) //
("reply_to", 0) //
("user", "john") //
("content", "post 1") //
);
t.push_action(
N(talk), N(post), N(jane),
mutable_variant_object //
("id", 2) //
("reply_to", 0) //
("user", "jane") //
("content", "post 2") //
);
t.push_action(
N(talk), N(post), N(john),
mutable_variant_object //
("id", 3) //
("reply_to", 2) //
("user", "john") //
("content", "post 3: reply") //
);
// Can't reply to non-existing message
BOOST_CHECK_THROW(
[&] {
t.push_action(
N(talk), N(post), N(john),
mutable_variant_object //
("id", 4) //
("reply_to", 99) //
("user", "john") //
("content", "post 3: reply") //
);
}(),
fc::exception);
}
FC_LOG_AND_RETHROW()
BOOST_AUTO_TEST_SUITE_END()
(7)重置链
删除已经存在的链并创建另外一个。首先进入用于出块的终端,按“ctrl+c”停止。
接着运行以下代码:
#删除现有链数据
rm -rf ~/eosio/chain
#初始化并启动新链
nodeos --config-dir ~/eosio/chain/config --data-dir ~/eosio/chain/data -e -p eosio --plugin eosio::chain_api_plugin --contracts-console
此时会发现会从0开始快速出块。
二 本地安装
环境准备
1.安装eosio
- 二进制安装
#Mac OS
brew tap eosio/eosio
brew install eosio
#Ubuntu18.04
wget https://github.com/EOSIO/eos/releases/download/v2.0.0/eosio_2.0.0-1-ubuntu-18.04_amd64.deb
sudo apt install ./eosio_2.0.0-1-ubuntu-18.04_amd64.deb
#Ubuntu16.04
wget https://github.com/EOSIO/eos/releases/download/v2.0.0/eosio_2.0.0-1-ubuntu-16.04_amd64.deb
sudo apt install ./eosio_2.0.0-1-ubuntu-16.04_amd64.deb
#CentOS
wget https://github.com/EOSIO/eos/releases/download/v2.0.0/eosio-2.0.0-1.el7.x86_64.rpm
sudo yum install ./eosio-2.0.0-1.el7.x86_64.rpm
- 源码安装
因为用的Ubuntu20.04,目前并没有可以支持的二进制文件,尝试采用源码安装方式(最后证明也不行,构建时不支持)。
(1)从github获取EOSIO源代码【下载较慢,建议休息时间下载】
官网推荐新建eosio文件夹
mkdir -p ~/eosio && cd ~/eosio
git clone --recursive https://github.com/EOSIO/eos
(2)更新子模块
cd eosio/eos
git submodule update --init --recursive
(3)获取变更信息
[git checkout <branch>] (optional)
git pull --recurse-submodules
2.安装CDT
CDT :Contract Dev. Toolkit合约开发工具包
ubuntu18.08安装方式:
wget https://github.com/EOSIO/eosio.cdt/releases/download/v1.6.3/eosio.cdt_1.6.3-1-ubuntu-18.04_amd64.deb
sudo apt install ./eosio.cdt_1.6.3-1-ubuntu-18.04_amd64.deb
3.使用钱包
钱包:公私钥对的存储库
(1)创建钱包
–file 选项可以避免钱包密码出现在终端(实际生产)
–to-console 创建默认钱包,页面显示密码(测试阶段)
$cleos wallet create --to-console
(2)开启钱包
默认情况下创建的钱包是关闭状态
#打开钱包
cleos wallet open
#返回钱包列表
cleos wallet list
如果运行正确,输出:
Wallets:
[
"default"
]
(3)解锁钱包
cleos wallet unlock
解锁成功后,会输出:
Wallets:
[
"default *"
]
(4)导入私钥到钱包
#生成私钥
cleos wallet creat_key
(5)导入开发密钥
每条EOSIO链都有默认的系统用户“eosio”,该账户通过加载用于指定管理和链共识的系统合约来启动链。每条新建的EOS链 拥有一个相同的开发密钥。
cleos wallet import
#提示输入私钥时输入:
5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3
4.启动keosd & nodeos
#启动keosd
keosd &
#启动nodeos
nodeos -e -p eosio \
--plugin eosio::producer_plugin \
--plugin eosio::producer_api_plugin \
--plugin eosio::chain_api_plugin \
--plugin eosio::http_plugin \
--plugin eosio::history_plugin \
--plugin eosio::history_api_plugin \
--filter-on="*" \
--access-control-allow-origin='*' \
--contracts-console \
--http-validate-host=false \
--verbose-http-errors >> nodeos.log 2>&1 &
启动成功后,进行必要的检查:
#检查节点是否正常出块
tail -f nodeos.log
#检查电子钱包,输出为Wallets:[]
cleos wallet list
#检查Nodeos端
#可以直接浏览器打开http://localhost:8888/v1/chain/get_info
#或者:
curl http://localhost:8888/v1/chain/get_info
5.创建测试账号
测试过程包括:
- 用户账号:bob、alice
- 默认账户:eosio
- 合约账户
#创建用户账号
cleos create account eosio bob YOUR_PUBLIC_KEY
cleos create account eosio alice YOUR_PUBLIC_KEY
#检查公钥--用户的关联
#注意:用户名(alice)是所有权的唯一标识,绑定的公钥变更 不会改变账户的所有权
#eosio授权机制比较特殊:owner密钥保持冷存储,当active被盗用时可以通过owner重获控制权。
cleos get account alice
合约开发
1.合约部署
(1)创建合约
contract目录中创建hello目录,新建hello.cpp
#include <eosio/eosio.hpp>
using namespace eosio;
class [[eosio::contract]] hello : public contract {
public:
using contract::contract;
[[eosio::action]]
void hi( name user ) {
print( "Hello, ", user);
}
};
(2)编译合约
eosio-cpp hello.cpp -o hello.wasm
(3)部署合约
#查看钱包内密钥
cleos wallet keys
#创建合约账户
cleos create account eosio hello YOUR_PUBLIC_KEY -p eosio@active
#部署合约
cleos set contract hello **CONTRACTS_DIR**/hello -p hello@active
(4)执行合约
#调用action
cleos push action hello hi '["bob"]' -p bob@active
#切换用户调用
cleos push action hello hi '["bob"]' -p alice@active
2.其他