这DAPP主要是实现一个小游戏的智能合约的实现,是为了提供学习EOS智能合约用。
1、编译智能合约,生成abi文件
eosiocpp -o mygame.wast mygame.cpp
eosiocpp -g mygame.abi mygame.cpp
2、部署智能合约
//创建3个用户账号
cleos create account eosio banker EOS6zzuh... EOS6zzuh...
cleos create account eosio player1 EOS6zzuh... EOS6zzuh...
cleos create account eosio player2 EOS6zzuh... EOS6zzuh...
//创建一个新游戏
cleos push action mygame.co creategame '["banker"]' -p banker
//玩家开牌
cleos push action mygame.co opencard '[6,1]' -p player1
cleos push action mygame.co opencard '[6,2]' -p player2
//查询数据表
cleos get table mygame.co mygame.co game
超级节点部署智能合约:
cleos set contract eosio /hom/.../contracts/eosio.bios -p eosio
创建一个智能合约文件
eosiocpp -n mytest
3、前端调用智能合约接口
import React from 'react'
import ReactDOM from 'react-dom'
import EOSJS from 'eosjs'
let contract_name = 'mygame.co'
let account_name = 'banker'
const EOSJS_CONFIG = {
contractName: contract_name, //合约名字
contractSender: account_name, //执行合约的账号(需要与私钥对应)
clientConfig:{
keyProvider:['5Jc...'], //账号对应的私钥
httpEndpoint: 'http://172.0.0.1:8888' //EOS节点程序的http终端
}
}
class LuckPoint extends React.Component {
constructor(props){
super(props)
this._initGameData = this._initGameData.bind(this)
this.gameprops = {
gameIndex: -1,
gameDataList: [];
loading_test: '正在读取数据...'
}
this.state = {
gameStatus: false,
winner: 0
}
}
componentDidMount(){
this._initGameData()
}
_initGameData(){
console.log('_initGameData::......')
this._updataGameData()
}
// cleos get tale luckpoint.co luckpoint.co game
_updataGameData(){
console.log('_updataGameData::......')
this._showLoading(true, '正在读取游戏数据... ...')
this.gameprops.gameIndex = -1
this.gameprops.gameDataList = []
//读取游戏数据
let eosjs = EOSJS.Localnet(EOSJS_CONFIG.clientConfig)
eosjs.contract(contract_name)
.then((contract)=>{
console.log('_updataGameData::'+contract_name+'合约加载成功!')
eosjs.getTableRows({"scope":contract_name, "code":contract_name, "table":"game","json":true})
.then(result => {
console.log('_updataGameData::读取游戏列表成功')
let rows = result.rows
let len = rows.length
for(let i=0; i<len; i++){
}
})
}).catch((err)=>{
console.log('_updataGameData::读取游戏列表失败')
})
}
// 调用智能合约
_createGame(){
console.log('_createGame::创建游戏...')
this._showLoading(true, '正在创建游戏... ...')
let _sender = account_name
let eosjs = EOSJS.Localnet(EOSJS_CONFIG.clientConfig)
eosjs.contract(EOSJS_CONFIG.contractName)
.then((contract)=>{
console.log('_createGame::加载合约成功')
contract.creategame(_sender, {authorization: [_sender] })
.then((res)=>{
console.log('_createGame::游戏创建成功')
this._updataGameData()
})
.catch((err)=>{
console.log('_createGame::游戏创建失败')
})
})
}
//开牌
_playerOpenCard(game_id, play_id){
console.log('_playerOpenCard::游戏ID'+game_id+', 玩家'+play_id+'开牌...')
this._showLoading(true, '玩家'+play_id+ '正在开牌...')
let _sender = account_name
let eosjs = EOSJS.Localnet(EOSJS_CONFIG.clientConfig)
eosjs.contract(EOSJS_CONFIG.contractName)
.then((contract)=>{
console.log('_playerOpenCard::加载合约成功')
contract.opencard(game_id, play_id, {authorization: [_sender]})
.then((res)=>{
console.log('_playerOpenCard::开牌成功')
this._updataGameData()
})
.catch((err)=>{
console.log('_playerOpenCard::开牌失败')
})
})
}
}
4、智能合约的实现
//mygame.hpp
#include <utility>
#include <vector>
#include <string>
#include <eosiolib/eosio.hpp>
#include <eosiolib/asset.hpp>
using eosio:asset;
class mygame: public eosio::contract {
public:
mygame(account_name self)
:eosio::contract(self), globals(_self, _self), games(_self, _self) {}
public:
void creategame(const account_name _owner);
void opencard(uint64_t _gameid, const uint32_t _player);
//测试函数
void sayhi(account_name receiver);
void printrand(uint64_t _gameid);
private:
void _checkgame(uint64_t _gameid);
void _finishgame(uint64_t _gameid);
uint32_t _getrandnum(uint64_t _gameid);
private:
//@abi table global i64 全局引用计数表
struct global{
uint64_t id = 0;
uint64_t nextgameid = 0;
uint64_t primary_key()const { return id; }
EOSLIB_SERIALIZE(global, (id)(nextgameid) )
};
//创建一个多索引容器的游戏引用计数,用于为新游戏生成ID
typedef eosio::multi_index<N(global), global> global_index;
global_index globals;
//@abi table game i64 游戏表
struct game {
uint64_t id; //游戏ID
uint32_t winner; //胜出者,0还未决胜负,1玩家1胜出,2玩家2胜出
uint32_t player1; //玩家1点数
uint32_t player2; //玩家2点数
time creattime; //创建时间
accunt_name owner; //创建游戏的账号
uint64_t primary_key()const { return id; } //设定数据主键
EOSLIB_SERIALIZE(game, (id)(winner)(player1)(player2)(creattime)(owner) )
};
//创建一个多索引容器的游戏列表
typedef eosio::multi_index<N(game), game> game_index;
game_index games;
};
///////////////////////////////////////////////////////////
//mygame.cpp
#include <mygame.hpp>
void mygame::creategame(const account_name _owner){
//创建一个全局引用计数器
auto global_itl = globals.begin();
if( global_itl == globals.end() ){
global_itl = globals.emplace(_self, [&](auto& gitr){
gitr.nextgameid = 0;
});
}
//增加引用计数器
globals.modify(global_itl, 0, [&](auto& gitr){
gitr.nextgameid++;
});
//创建一个新游戏对象
auto game_itr = games.emplace(_self, [&](auto& new_game){
new_game.id = global_itl->nextgameid;
new_game.winner = 0;
new_game.player1 = 0;
new_game.player2 = 0;
new_game.createtime = now();
new_game.owner = _owner;
});
}
void mygame::opencard(uint64_t _gameid, const uint32_t _player){
eosio_assert(_player == 1 || _player == 2, "the player must is 1 or 2.");
auto game_itr = games.find(_gameid);
eosio_assert(game_itr != games.end(), "game not found");
//修改游戏状态
games.modify(game_itr, 0, [&](auto& gitr){
if(_player == 1){
gitr.player1 = 1;
} else if(_player == 2){
gitr.player2 = 1;
}
//检查游戏是否已经决出胜者
_checkgame(_gameid);
});
}
void mygame::sayhi(account_name receiver){
eosio::print("hi~ luck point world!");
}
void mygame::printrand(uint64_t _gameid){
eosio::print("printrand::%d",_getrandnum(_gameid));
}
void mygame::_checkgame(uint64_t _gameid){
auto game_itr = games.find(_gameid);
eosio_assert(game_itr != ggames.end(), "game not found");
if(game_itr->player1 != 0 && game_itr->player2 !=0){
games.modify(game_itr, 0, [&](auto& gitr){
gitr.winner = _getrandnum(_gameid);
});
}
}
uint32_t mygame::_getrandnum(uint64_t _gameid){
auto game_itr = games.find(_gameid);
eosio_assert(game_itr != games.end(), "game id not found in games");
//随机数=游戏创建时间,取余2,再+1,保证是1、2中的任意一个
return (((uint32_t)(game_itr->createtime))%2) + 1;
}
EOSIO_ABI( mygame, (creategame)(opencard)(sayhi)(printrand))