EOS-学习笔记002-智能合约

上个笔记我们搭建好了开发环境,这次我们来写一个简单的合约。
写之前需要创建 wallet 和账户。

首先看一下都有哪些参数可用

cleos wallet

本篇笔记涉及到的内容:

  1. 创建 wallet
  2. 创建账户
  3. 创建合约
  4. 发布合约
  5. 写测试案例

编码规范

Coding Standards

Type Standardized Method
Structs lower case with _ between words including constants
Classes lower case with _ between words including constants
Methods lower case with _ between words including constants
Types lower case with _ between words including constants
Template Arguments CamelCase, no spaces
Macros UPPERCASE

Comment Blocks

/*
Comment Block
Comment Block
*/

Inline Comments /** Comments **/

Standard Account Names

  • Can only contain the characters .abcdefghijklmnopqrstuvwxyz12345. a-z (lowercase), 1-5 and . (period)
  • Must start with a letter
  • Must be 12 characters

Table Names, Structs, Functions, Classes

  • Can only contain up to 12 alpha characters

Symbols

  • Must be capitalized alpha characters between A and Z
  • Must be 7 characters or less

创建一个 wallet

cleos wallet create -n testwallet --to-console

Creating wallet: testwallet
Save password to use in the future to unlock this wallet.
Without password imported keys will not be retrievable.
"PW5K6dE8RxWfHdoWc96YDAcVhvvHeu1J1PapcBLtZVXuLt1s2y5CN"

返回一个用于解锁钱包的密码。然后我们需要导入私钥

随机生成一个公私钥对
cleos create key --to-console

私钥: 5JBSnaNR9gKDBxq5TqE9yaX88w4gUPZfcT2WniB7BixBBWMozcK
公钥: EOS6Ax2grsDJiCxvg3n1LCLx68wt2SzfCG1meTMsyVbKrtWRKJyqw

cleos wallet unlock -n testwallet

cleos wallet import -n testwallet \
--private-key 5JBSnaNR9gKDBxq5TqE9yaX88w4gUPZfcT2WniB7BixBBWMozcK

//this is eosio account private key
cleos wallet import -n testwallet \
--private-key 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3

wallet 相关操作

cleos wallet open
cleos wallet list
cleos wallet unlock

cleos wallet unlock -n testwallet --password PW5K6dE8RxWfHdoWc96YDAcVhvvHeu1J1PapcBLtZVXuLt1s2y5CN

创建账号

Usage: ./cleos create account [OPTIONS] creator name OwnerKey ActiveKey

cleos create account eosio acct1 EOS6Ax2grsDJiCxvg3n1LCLx68wt2SzfCG1meTMsyVbKrtWRKJyqw
cleos create account eosio acct2 EOS6Ax2grsDJiCxvg3n1LCLx68wt2SzfCG1meTMsyVbKrtWRKJyqw

查询账号 EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
cleos get accounts EOS6Ax2grsDJiCxvg3n1LCLx68wt2SzfCG1meTMsyVbKrtWRKJyqw

查看账户信息
cleos get account acct1

创建合约 - use eosfactory with vscode

先把系统合约 eosio.token 部署上去,然后就可以创建 token 了。
再部署合约之前,必须创建一个账户用来承载部署的合约。

先下载这里的合约,eos 工程里面的是旧版的。
git clone https://github.com/EOSIO/eosio.contracts/

cleos create account eosio eosio.token EOS6Ax2grsDJiCxvg3n1LCLx68wt2SzfCG1meTMsyVbKrtWRKJyqw

eosio-cpp ~/eosio.contracts/eosio.token/src/eosio.token.cpp -o eosio.token.wasm --abigen
eosiocpp -o ./app.wast ~/eos/contracts/eosio.token/eosio.token.cpp
eosiocpp -g token.abi token.cpp

如果报错: _S_create_c_locale name not valid
执行这个:export LC_ALL="C"

cleos set contract eosio.token /home/ubuntu/eosio.contracts/build/eosio.token -p eosio.token@active

创建 token

//创建 token
cleos push action eosio.token create '[ "eosio", "1000000000.0000 EOS"]' -p eosio.token@active

// 发行 token
cleos push action eosio.token issue '[ "acct1", "100.0000 EOS", "for test" ]' -p eosio@active

// 转账 2147483648
cleos push action eosio.token transfer '[ "acct1", "acct2", "100.0000 EOS", "trans test" ]' -p acct1@active
cleos push action eosio.token transfer '{"from":"token","to":"eosio","quantity":"20.0000 TKN","memo":"my first transfer"}' -p token

创建合约

ref

这里使用 vscode 来做 IDE,把eos/contracts/eosio.token复制过来

新建 makefile,注意使用 tab 缩进,否则会提示错误

# Makefile for an eosio smart contact

CC=eosiocpp
Contract=mw-coin

all:
@echo "Building"
# $(CC) $(Contract).cpp -o $(Contract).wasm --abigen
$(CC) -o $(Contract).wast $(Contract).cpp

clean:
rm -f $(Contract).wast
# rm -f *.abi
rm -f $(Contract).wasm

deploy:
cleos wallet unlock -n testwallet --password PW5K3Uwa3Dm73B9gnPMCyYD4TZKwkWVpMbxPojnL7E1Lz4RddkoA4
cleos set contract mistywest ../$(Contract) -p mistywest@active

includePath 里面添加 eosiolib 的路径。

新建一个 task.json,添加两个 task,一个 build 用于生成 wasm, 一个 deploy 用于发布合约

{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "mw-coin build",
"type": "shell",
"command": "make",
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "mw-coin deploy",
"type": "shell",
"command": "make deploy",
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

编译 wasm/wast 的时候,使用快捷键 command+shift+B,选择mw-coin build
发布合约的时候,使用快捷键 command+shift+B,选择mw-coin deploy

调用合约

mistywest 是合约的账户,create 是合约的函数,[…]是参数,-p 是使用 mistywest 签名该 action

// unlock wallet
cleos wallet unlock -n testwallet --password PW5K3Uwa3Dm73B9gnPMCyYD4TZKwkWVpMbxPojnL7E1Lz4RddkoA4

// create token
cleos push action mistywest create \
'["mistywest", "1000.00 MWC"]' -p mistywest@active

// issue token to walker
cleos push action mistywest issue \
'["walker", "10.00 MWC", "Hi Walker!"]' -p mistywest@active

// check balance
cleos get currency balance mistywest walker MWC

目前该合约已经实现了创建 token 和发布 token 的功能,下面添加投票功能

合约增加投票功能

在 hpp 里面添加

[[eosio::action]] void openpoll(int poll_number,
string poll_desc);
[[eosio::action]] void addvoter(account_name newvoter);
[[eosio::action]] void vote(int poll_number,
int desc);
struct [[eosio::table]] voter_table
{
account_name voter;
uint64_t primary_key() const { return voter; }
};
typedef eosio::multi_index<N(votertable), voter_table> voter

[[eosio::action]] 是 c++ 属性,用来生成 abi 文件
Multi Index Table 是用来在区块链上持久化数据的,保存 voter 的列表,同时使用 “voter” 作为主键

void mw::addvoter(account_name newvoter)
{
require_auth(_self);

votertable voterTable(_self, newvoter);
voterTable.emplace(_self, [&](auto &s) {
s.voter = newvoter;
});
}
void mw::openpoll(int poll_number, string poll_desc)
{
}
void mw::vote(int poll_number, int desc)
{
}

EOSIO_ABI( eosio::mw, (addvoter)(create)(issue)(transfer) )

require_auth(_self) 是说在调用之前需要 mistywest 对这个 action 签名授权
然后是声明 voter table 第一个参数时 “owner”,第二个参数是 “scope”。

手动添加 abi 文件
structs

,
{
"name": "addvoter",
"base": "",
"fields": [
{"name":"newvoter", "type":"account_name"}
]
},{
"name": "voter_table",
"base": "",
"fields": [
{"name":"voter", "type":"account_name"}
]
}

actions

,{
"name": "addvoter",
"type": "addvoter",
"ricardian_contract": ""
}

tables

,
{
"name": "votertable",
"type": "voter_table",
"index_type": "i64",
"key_names" : ["voter"],
"key_types" : ["uint64"]
}

添加投票人

cleos push action mistywest addvoter \
'["walker"]' -p mistywest@active

现在有一个表存在的区块链上的某个地方,可以查询

cleos get table mistywest walker votertable

mistywest 是owner,walker 是 scope,votertable 是表名