Oasis(绿洲)

在我们开始使用代码之前,我们首先需要一个想法。你看过Steven Spielberg的“Ready Player One”电影吗?如果你确实已经知道了绿洲是什么!精彩,对吧?让我们想象一下,我们是将要建立下一个Oasis的团队的一部分,我们的任务是将区块链技术集成到其中,或者至少表明可以完成。我们要做的是一个小型的dApp,它会有玩家。每个玩家都可以玩游戏,并且可以从中获得硬币。随着硬币,他可以去市场购买物品,这会给体力,能力,生命 ,升级。当然,Oasis合同是我们的主要起点。

开发前准备

为了能够开发EOS dApps,您需要使用C / C ++的背景,因为这是用于EOS Smart Contracts的编程语言

  • 会使用C / C ++ -

一个IDE,您可以在其中编写智能合约。我们使用VS Code和C / C ++扩展,但是你可以选择最适合你的。CLion也是一个非常不错的选择

当然,你需要一个本地testnet节点,但你知道如何构建一个。

  • 一个工作的本地测试网络节点 -

配置开发环境

在编写我们的第一份合同之前,我们需要在开发过程中设置一些我们需要的东西。

步骤1 - 启动节点

nodeos -e -p eosio --plugin eosio :: wallet_api_plugin --plugin eosio :: chain_api_plugin --plugin eosio :: account_history_api_plugin --resync 

步骤2 - 创建一个电子钱包

它将存储我们在签署交易时使用的密钥

# 1. Create new wallet with the name "oasis"
cleos wallet create -n oasis

# 2. Generate two pair of keys (use the command twice)
cleos create key

# 3. Import the generated private keys in the wallet(you need to specify the wallet at the end)
# {private_key_1} - This will be the OwnerKey
# {private_key_2} - This will be the ActiveKey
cleos wallet import {private_key_1} -n oasis 
cleos wallet import {private_key_2} -n oasis 

# 4. Add the private key of the "eosio" account into your wallet
# Note: With the latest version of EOSIO the private key is automatically added to your wallet
cleos wallet import 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3 -n oasis

注意:不要忘记保存您的密钥和钱包密码
EOS.IO智能合约在帐户上运行。因此,需要账户将交易转移或以其他方式推送至区块链。让我们将我们的帐户命名为“ anorak ”。听起来很熟悉?

# Create the account using the public keys
cleos create account eosio anorak {public_OwnerKey} {public_ActiveKey}

# "eosio" is the name of the account who will create the new one
# "anorak" is the name of the new account

项目'绿洲'

现在是开始开发我们的dApp的时候了!创建一个名为Oasis的项目文件夹。里面添加两个主要的子文件夹 - contracts 和 tests。是的,我们也要写tests。将会有四个子文件夹:Players, Games, Marketplace , Oasis。

Player智能合约

玩家将成为我们的第一个EOS智能合约。每个玩家将拥有用户名,等级,生命值,能量值,金币,背包和天赋。他将能够用金币从商店购买物品,并将其添加到他的背包,生命值,能量值或天赋中。为了获得金币,他需要与绿洲的其他玩家一起玩游戏

在Players文件夹中创建Players.hpp和Players.cpp文件

  1. Player.hpp是包含由.cpp文件引用的变量,常量和函数的头文件。

  2. Player.cpp文件是包含合同功能的源文件。

我们来深入看一下EOS合约的基本结构

Players.hpp
#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>
#include <string>
Players.cpp

在合约开始时,我们设置了我们要使用的所有包含。在我们的例子中,Players.hpp已经拥有了它们,所以在我们的合同实现中只包含头文件就足够了。大多数情况下,当你使用头文件时你会这样做。

将所有内容都包装在名称空间中是一种很好的做法,因为它与Oasis一起显示在这里。

#include "Players.hpp"

namespace Oasis {
    using namespace eosio;
    using std::string;

    class Players : public contract {
        using contract::contract;
        
        public:
            Players(account_name self):contract(self) {}

            //@abi action
            void add(const account_name account, string& username, uint64_t level) {
                
            }

            //@abi action
            void update(const account_name account) {

            }

            //@abi action
            void getplayer(const account_name account) {
                
            }

        private:

            //@abi table player i64
            struct player {
                uint64_t account_name;
                string username;
                uint64_t level;
                uint64_t health_points = 1000;
                uint64_t energy_points = 1000;

                uint64_t primary_key() const { return account_name; }

                EOSLIB_SERIALIZE(player, (account_name)(username)(level)(health_points)(energy_points))
            };

            typedef multi_index<N(player), player> playerIndex;
    };

    EOSIO_ABI(Players, (add)(update)(getplayer))
}

该Players 继承contract ,并使用它的构造函数(using contract::contract)。

在开发EOS dApp时,您应该了解的一件重要事情是,智能合约以操作和共享内存数据库访问的形式相互通信。一个合同可以读取另一个合同数据库的状态,只要它包含在具有异步可达的事务的读取范围内。这可以通过使用两种通信模式之一来实现 - inline 和deferred。您可以将它们视为同步和异步

从EOS.IO文档:

inline - 内联保证与当前交易函数一起执行或展开; 无论成功或失败,都不会收到任何通知。内联与原始交易函数具有相同的范围和权限
deferred - 延期将在稍后由生产者自行决定; 可以传达通信结果或者可以简单地超时。延期可以延伸到不同的范围,并承担发送它们的合同的权力。
在我们合同的类体中,有两种类型的访问修饰符 - public和private。在公共部分是构造函数和所有动作。一个动作表示智能合约中的单个操作。在我们的合同中,我们add,update和getplayer。我们稍后会看看他们。与此同时,您应该已经注意到,在每个函数之前,我们都有“ // @ abi action ”。它是eosiocpp脚本的指示标志,它将为我们的智能合约生成.abi文件。

在private中,我们保存我们不希望从Player合约外部访问的所有内容。这里我们正在初始化multi_index。这是什么,为什么我们需要它?
//@abi table player i64
struct player {
  uint64_t account_name;
  string username;
  uint64_t level;
  uint64_t health_points = 1000;
  uint64_t energy_points = 1000;

  uint64_t primary_key() const { return username; }

  EOSLIB_SERIALIZE(player, (account_name)(username)(level)(health_points)(energy_points))
};

typedef multi_index<N(player), player> playerIndex;

Actions 实现

add 负责创建一个玩家

/@abi action
void add(const account_name account, string& username) {
    /**
     * We require that only the owner of an account can use this action
     * or somebody with the account authorization
    */
    require_auth(account);

    /**
     * We access the "player" table as creating an object of type "playerIndex"
     * As parameters we pass code & scope - _self from the parent contract
    */
    playerIndex players(_self, _self);

    /**
     * We must verify that the account doesn't exist yet
     * If the account is not found the iterator variable should be players.end()
    */
    auto iterator = players.find(account);
    eosio_assert(iterator == players.end(), "Address for account already exists");

    /**
     * We add the new player in the table
     * The first argument is the payer of the storage which will store the data
    */
    players.emplace(account, [&](auto& player) {
        player.account_name = account;
        player.username = username;
        player.level = 1;
        player.health_points = 1000;
        player.energy_points = 1000;
    });
}

update 负责更新玩家level, health and energy points . 实现和add相似,只是在更新玩家状态时第一个参数时迭代器

//@abi action
void update(account_name account, uint64_t level, int64_t healthPoints, int64_t energyPoints) {
    require_auth(account);

    playerIndex players(_self, _self);

    auto iterator = players.find(account);
    eosio_assert(iterator != players.end(), "Address for account not found");

    /**
     * We add the new player in the table
     * The first argument is the payer of the storage which will store the data
    */
    players.modify(iterator, account, [&](auto& player) {
        player.level = level;

        if ((player.health_points - healthPoints) < 0) {
            player.health_points = 0;
        } else {
            player.health_points -= healthPoints;
        }

        if ((player.energy_points - energyPoints) < 0) {
            player.energy_points = 0;
        } else {
            player.energy_points -= energyPoints;
        }
    });
}

getplayer 是一个查询操作,任何人都可以访问 ,不需要认证

//@abi action
void getplayer(const account_name account) {
    playerIndex players(_self, _self);

    auto iterator = players.find(account);
    eosio_assert(iterator != players.end(), "Address for account not found");

    /**
     * The "get" function returns a constant reference to the object
     * containing the specified secondary key
    */
    auto currentPlayer = players.get(account);
    print("Username: ", currentPlayer.username.c_str(), " Level: ", currentPlayer.level, " Health: ", currentPlayer.health_points, " Energy: ", currentPlayer.energy_points);
}

Player智能合约部署

生成wast和abi

//生成wast
eosiocpp -o Players.wast Players.cpp
//生成abi
eosiocpp -g Players.abi Players.cpp

部署

# cleos set contract {account} {path_to_contract_folder} {path_to_.wast_file} {path_to_.abi_file}
cleos set contract anorak ./contracts/Players ./contracts/Players/Players.wast ./contracts/Players/Players.abi
Reading WAST...
Assembling WASM...
Publishing contract...
executed transaction: b3fd7968d08f3e1cece14fed9632c8c678e89f5832b356a3c4c651aa4d3fe159  5668 bytes  10000 cycles
#         eosio <= eosio::setcode               "000000004073e9340000cf590061736d0100000001cf011d60037f7e7f0060057f7e7e7e7e0060027f7e0060000060057e7...
#         eosio <= eosio::setabi                "000000004073e934000406706c6179657200050c6163636f756e745f6e616d650675696e74363408757365726e616d65067...

测试

创建一个玩家
# cleos push action {account} {action_name} '{data}' -p {account}@active
cleos push action anorak add '["anorak","art3mis"]' -p anorak@active

executed transaction: 9b099bd072d090424bff9cff3e0473a2ccde98d3554cbffee2392172e4221055  252 bytes  1000 cycles
#        anorak <= anorak::add                  {"account":"anorak","username":"art3mis"}
查询玩家
# cleos push action {account} {action} {data}
# account - The account providing the contract to execute
# action - The action to execute on the contract
# data - The arguments to the contract
cleos push action anorak getplayer '["anorak"]'

executed transaction: 5ecdf264952837e61671b31e935eec6365af8c6430f00f3eafd274e7ca81910d  156 bytes  1000 cycles
#        anorak <= anorak::getplayer            {"account":"anorak"}
>> Username: art3mis Level: 1 Health: 1000 Energy: 1000
更新玩家状态
cleos push action anorak update '["anorak",4,75,110]' -p anorak@active

executed transaction: 0da802b784e9bc2d56d84582e269eae213f6255ca2bbe83c32b6baf9fafc1f54  268 bytes  1000 cycles
#        anorak <= anorak::update               {"account":"anorak","level":4,"healthPoints":75,"energyPoints":110}
验证更新
cleos push action anorak getplayer '["anorak"]' -p anorak@active

executed transaction: a82c8356aaaea39ddb544d0fc5486f567c4bbdbb887b752aaf21ff0dd9ee8772  156 bytes  1000 cycles
#        anorak <= anorak::getplayer            {"account":"anorak"}
>> Username: art3mis Level: 4 Health: 925 Energy: 890

总结

from:https://infinitexlabs.com/eos-development-tutorial-part-1/

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • 1 EOS智能合约的介绍1.1 所需背景知识1.2 EOS智能合约基础知识1.3 技术局限性 2 智能合约文件2....
    cenkai88阅读 30,480评论 5 28
  • 1. 账户与钱包1.1 创造并管理钱包1.2 生成EOS Keys并导入1.3 备份您的钱包1.4 创建账户 2....
    cenkai88阅读 3,927评论 1 7
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • 学习区块链,最刺激的莫过于发币,第一篇文章里介绍了如何搭建EOS开发环境,第二篇文章我们已经介绍了如何部署调用合约...
    P叔阅读 4,694评论 5 6
  • 从来没有认真的看过一朵花的开放,或许是自己太匆忙,红尘中的人们总是来也匆匆,去也匆匆。许多的美丽因此被错过,一旦回...
    郑子衿阅读 592评论 3 7