在之前的教程中,我们学习了如何设置开发环境来构建EOS。我们启动了本地测试网络,部署了一个示例EOS智能合约并与之交互。您可以在我们的EOS区块链开发系列的第一个教程中找到所有内容。
我们要做的是一个小型的dApp,它会有玩家。每个玩家都可以玩游戏,并且可以从中获得硬币。随着硬币,他可以去市场购买物品,这会给他力量,能力,健康和/或水平。当然,Oasis合同是我们的主要合同工具。
我们需要的工具:
为了能够开发EOS dApps,您需要懂得使用C / C ++技术开发,因为这是用于EOS Smart Contracts的编程语言
C / C ++
IDE
一个工作的本地测试网络节点
搭建环境
在编写我们的第一份合同之前,我们需要在开发过程中设置一些我们需要的参数。
步骤1 - 启动节点
# 默认情况下将合同的输出到控制台中:
# --contracts-console
nodeos -e -p eosio --plugin eosio::wallet_api_plugin --plugin eosio::chain_api_plugin --plugin eosio::history_api_plugin --contracts-console
步骤2 - 创建钱包
它将存储我们在签署交易时使用的密钥
#1.钱包命名为"oasis"
cleos wallet create -n oasis
#2.生产2对密钥(使用该命令2次)
cleos create key
#3.将生成的私钥导入钱包(您需要在最后指定钱包)
# - 这是拥有者私钥
# - 这是活动密钥
cleos walletimport-n oasis
cleos walletimport-n oasis
#4.将“eosio”帐户的私钥添加到您的钱包中
#注意:使用最新版本的EOSIO,私钥会自动添加到您的钱包中
cleos walletimport5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3 -n oasis
步骤3 - 创建账号
EOS.IO智能合约在账户上运行。 因此,账户需要将交易转移或以其他方式推送至区块链。 让我们将我们的账户命名为“anorak”。
# 创建账号使用的公钥
cleos create account eosio anorak
#“eosio”是将创建新账户的账户的名称
#“anorak”是新账户的名称
项目'Oasis'
现在是开始开发我们的dApp的时候了!创建一个名为Oasis的项目文件夹,里面添加两个主要的子文件夹 - 合同和测试,再建四个子文件夹:玩家,游戏,市场和绿洲。
玩家智能合同
玩家将成为我们的第一个EOS智能合约。每个玩家将拥有用户名,等级,健康点,能量点数,余额,库存(全部物品)和能力。他将能够从市场购买物品,并将其添加到他的库存,生命值,能量点和/或能力中。为了获得硬币,他需要与Oasis的其他玩家一起玩游戏。
在Players文件夹中创建Players.hpp&Players.cpp文件
1. Player.hpp是包含由.cpp文件引用的变量,常量和函数的头文件。
2. Player.cpp文件是包含合同功能的源文件。
我们来深入看一下EOS合约的基本结构
Players.hpp
#include
#include
#include
注意:我们现在只需要在Players.hpp中添加包含,目前不会在其他合约中使用。
Players.cpp
在合同开始时,我们设置了我们要使用的所有包含。 在我们的例子中,Players.hpp已经导入它们,所以在我们的合同实现中只包含头文件就足够了。 将所有内容都包装在名称空间中是一种很好的做法,因为它与Oasis一起显示在这里。
如果你熟悉C ++,你可能知道为什么在类实现前我们有两个using子句。 对于其他人 - 当我们想从C ++的eosio命名空间中调用一个动作时,我们必须像这样调用它:eosio :: some_action(),以避免在动作名称前添加eosio :: everytime 在开始时使用名称空间eosio添加。
#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(constaccount_name account,string& username, uint64_t level) {
}
//@abi action
void update(constaccount_name account) {
}
//@abi action
void getplayer(constaccount_name account) {
}
private:
//@abi table player i64
structplayer {
uint64_t account_name;
stringusername;
uint64_t level;
uint64_t health_points =1000;
uint64_t energy_points =1000;
uint64_t primary_key()const{returnaccount_name; }
EOSLIB_SERIALIZE(player, (account_name)(username)(level)(health_points)(energy_points))
};
typedef multi_index playerIndex;
};
EOSIO_ABI(Players, (add)(update)(getplayer))
}
Players类继承“合约”智能合约并使用其构造函数(使用contract :: contract)
在开发EOS dApp时,您应该了解的一件重要事情是,智能合约以操作和共享内存数据库访问的形式相互通信。一个合同可以读取另一个合同数据库的状态,只要它包含在具有异步的事务的读取范围内。这可以通过使用两种通信模式之一来实现 - 内联或延迟。您可以将它们视为同步和异步;
EOS.IO文档:
内联 - 内联保证与当前交易一起执行或展开;无论成功或失败,都不会通知任何通知。内联与原始交易具有相同的范围和权限
延期 - 延期将在稍后由发行人自行决定;可以传达通信结果或者可以简单地超时。延期可以延伸到不同的范围,并承担发送它们的合同的权力。
在我们合同的类体中,有两种类型的访问修饰符 - public和private。在公共部分是构造函数和所有动作。一个动作表示智能合约中的单个操作。在我们的合同中,我们添加,更新和getplayer。我们稍后会看看他们。同时,您应该已经注意到,在每次操作之前,我们都有“// @ abi action”。它是eosiocpp脚本的指示标志,它将为我们的智能合约生成.abi文件。
在隐私部分,我们保留的所有内容不希望外部玩家合同访问。这里我们正在初始化multi_index。这是什么,为什么我们需要它?
//@abi table player i64
structplayer {
uint64_t account_name;
stringusername;
uint64_t level;
uint64_t health_points =1000;
uint64_t energy_points =1000;
uint64_t primary_key()const{returnusername; }
EOSLIB_SERIALIZE(player, (account_name)(username)(level)(health_points)(energy_points))
};
typedef multi_index playerIndex;
正如我们所说的,一个行动代表了智能合约中的单一操作。每个行动都在其自己的环境中运作,称为行动环境。上下文提供了执行该操作所需的几件事情。其中一件事是行动的工作记忆。这是行动维持其工作状态的地方。在处理动作之前,EOSIO为动作建立一个干净的工作记忆。在新操作的上下文中执行另一个操作时可能已设置的变量不可用。在行动中传递状态的唯一方法是将其持久存储并从EOSIO数据库中检索。
这可以通过多索引来实现,它允许我们读取和修改EOSIO数据库中的持久状态。
在我们的合同中,我们已经为多索引表声明了一个名为player的对象模板。需要注意的是,当我们为表格创建模板时,我们还需要添加primary_key。我们使用account_name,因为我们希望每个账户有一个玩家
我们还为eosiocpp脚本提供了一个指示标志 - “// @ abi桌面播放器i64”。我们说我们表的名字是玩家,而使用的索引类型是i64。
一旦对象准备就绪,我们需要使用以下模板键入我们的多索引:
您可能想知道EOSLIB_SERIALIZE和EOSIO_ABI是什么。
注:代码部分可滑动
这些是C ++宏。 EOSIO_ABI封装了apply方法的逻辑。 apply为动作处理程序,它监听所有传入的动作并根据函数中的规范作出反应。 宏的结构非常简单。 第一个参数是类型(当前类的名称),下一个参数是下面示例中列出的所有操作
// EOSIO_ABI(class_name, (action_1)(action_2)(action_3)...(action_n))
EOSLIB_SERIALIZE宏提供序列化和反序列化方法,以便可以在合约和nodeos系统之间来回传递操作。
// EOSLIB_SERIALIZE(struct_name, (property_1)(property_2)(property_3)...(property_n))
领取专属 10元无门槛券
私享最新 技术干货