查看原文
其他

教程 | 你的第一个Truffle分布式app (4)

2017-11-10 Hugh Knight 以太坊爱好者

教程 | 你的第一个Truffle分布式app (1)
教程 | 你的第一个Truffle分布式app (2) 
教程 | 你的第一个Truffle分布式app (3) 

阅读科技文章或者博客的时候总会遇到一些挑战,但另一方面(观察我做的事情的话),我发现对作者来说,其中一个最困难的部分是尝试决定在什么时候以及如何介绍特定的部分和特定的观念。

很多时候,我们尝试尽可能快地说明如何创建一个交互界面。我没有骗你,看着代码的视觉结果是激动人心的,而且这也让你觉得自己正在取得快速的进展。

但我跳过了交互的部分,也不建议你过于投入到交互界面。让我来告诉你为什么:

  1. 有些时候,你过于沉迷于尝试让前端看起来跟你想要的一致,而忽略了后端;

  2. 如果我们对前端讨论得太多,我们有可能忘记我们真正想要实现的东西,还一边喋喋不休“如果我加入这个输入框,或者让它淡出,不是很酷吗”,等等。

说明了这些,我们将开始在我们的项目里创建和管理一个合约。我知道,这不会是一个提神醒脑的话题,但如果我们可以放慢一点并且获得一些认识的话,这将有助于我们为未来建立一个对Dapp的坚实的理解。

Solidity

记分牌Dapp的一个主要功能是玩家列表。没有把那些名字展示在交互界面上,我们就什么也做不了。我认为这是一个很棒的起点。现在,这个Dapp只是由一个静态的JSON(JavaScript Object Notation)文件所驱动,这给了我们两件需要思考的事情:

  1. 我们到底想把那些跟每一个玩家对应的数据储存在哪里?

  2. 然后,我们如何能够在记分牌界面中显示这些信息,而不是直接显示JSON数据?

我们将在后面的推送中回到第二个问题,但是,说到第一个问题:“我们到底想把那些跟每一个玩家对应的数据储存在哪里”,正确的回答是:使用一个智能合约,“存在以太坊(Ethereum)区块链上”。

具体而言,我们将创建一个结构体(struct),包含用来定义一个玩家的每一种类型的数据。

给你的提示:到底什么是结构体?——“结构体”就是一种数据类型,用以代表拥有多种潜在不同类型属性的实体。

打个比方:

struct Dog {   string name;   string breed;   string color;   uint age; }

要做到这件事,让我们在“contracts”文件夹里创建一个文件,并且给它命名“Users.sol”。

每个人都有他自己的编程风格,所以,你没有必要跟我做一样的事情。但在我开始编程之前我经常做的一件事,是在我想实现的文件中创建一个简单的架构。

现在,让我们沿着列表,把代码剩下的部分列出来。

//定义我们的软件版本

pragma solidity ^0.4.15;

//初始化我们的合约(不要忘记了右括号)

contract Users {}

//创建我们的用户结构体

struct Participant {        uint id;        bytes32 name;        uint point;    }

//定义我们的统计变量

Participant[] public users; uint userCount;

//加入新的用户

function addUser(bytes32 userName, uint userPoint) returns (uint userID, bool success) {    userID = userCount++;    Participant memory newUser;    newUser.id = userID;    newUser.name = userName;    newUser.point = userPoint;    users.push(newUser);    return(userID, true); }

//获得用户列表

function getUsers() constant returns (uint[], bytes32[], uint[]) {    uint length = users.length;    uint[] memory usersID = new uint[](length);    bytes32[] memory userNames = new bytes32[](length);    uint[] memory userPoints = new uint[](length);    for (uint i = 0; i < users.length; i++) {        Participant memory showUser;        showUser = users[i];        usersID[i] = showUser.id;        userNames[i] = showUser.name;        userPoints[i] = showUser.point;    }    return(usersID, userNames, userPoints); }

// 为用户改变总点数

function plusFive(uint id) returns (bool success) {    users[id].point = users[id].point + 5;    return true; }

该图展示了上文编程过程

你的代码应该看起来像这条“给你的提示”:在Solidity中,一个函数无法返回一个结构体,所以你必须返回一个数组的数组。字符串可能是任意长度,这在Solitidy中是个问题,所以我们不得不使用bytes32将字符串变为固定长度。通过将它转为十六进制,我们保证在Solidity中我们没有制造任何问题。

编译与迁移

现在我们已经写好了我们的合约,让我们用回Truffle来帮助我们编译、迁移,并将我们的合约部署到TestRPC区块链上,使得我们可以与它互动。

保存好我们的“User.sol”文件后,我们想做的第一件事情就是让Truffle知道,在我们的迁移中要部署什么文件。现在打开迁移目录。在那儿你将看到,第一个文件是“1_inital_migration.js”,这一文件处理合约“Migrations.sol”,用于观察其它合约迁移过程。我们可以把它放在一边,创建一个新文件,叫做“2_deploy_contract.js”,帮助我们部署用户合约。

要实现这一点,让我们输入下列代码:

var Users = artifacts.require("./Users.sol");module.exports = function(deployer) {    deployer.deploy(Users); };

这里,我们正在告诉Truffle我们正在与哪一个合约互动,通过使用“artifacts.require()”方法。

  1. 使用module.exports,输出我们的函数。

  2. “deployer.deploy()”帮助我们安排我们的部署任务。

现在我们已经告诉了Truffle我们想做什么,我们可以在命令提示符或是Terminal终端上运行迁移指令以及编译指令了。

在Terminal终端上,运行如下代码:

truffle compile

这就是我们用来编译合约的指令。我们会有一个近似于下图的结果:

Truffle编译结果

然后,在你的命令行提示符中运行下列指令:

truffle migrate

你将看到下列结果:

Truffle迁移结果

如果你收到一个报错的信息说无法连接到以太坊客户端,这只意味着你的TestRPC没有在运行。如果你曾经在另一个命令提示符窗口中停止运行它,使用“testrpc”指令重新启动它,然后尝试再次运行“truffle migrate”。

数据交互

当我们想在Truffle上与我们的部署互动的时候,我们使用Truffle控制台。我们可以通过在Terminal终端上运行下列指令来启动它:

truffle console

当我们将我们的后端(合约)与前端在一个Dapp中连接起来的时候,我们要达到两个目的。

  1. 这个被部署的合约必须有个ABI(application binary interface,应用二进制接口)。

  2. 它同样拥有一个在区块链上的地址。

所以,让我们进一步去验证这两件东西,以保证我们可以移动一者。要检查你的合约的ABI,在Truffle控制台上运行下列代码:

Users.abi

Truffle上运行Users.abi的结果

我们所做的就是告诉Truffle,在我们的“Users”部署中,向我们显示“ABI”信息。

让我们通过在Truffle控制台中输入下列代码来获得我们合约的信息:

Users.address

Truffle中Users的地址结果

你的结果可能与我的结果有所不同,但是恭喜你!你已经使用Truffle开发出了你的第一个合约到区块链(测试网络)上。伟大的一步,花一分钟庆祝一下!

时间到!我知道你真正想看到的是什么,所以,让我们再深入一点。

发现数据

这将是快速与激情的时刻,让我们输入一些用户数据,并在控制台中查询它。在控制台上工作可能会有点繁琐。所以我会看一下这个链接,以读出为什么它是以这种方式工作的:Changes from truffle 2 to 3。

要把一些用户数据添加进合约,在Truffle控制台中写出下列指令:

Users.deployed().then(function(instance){instance.addUser("john", 26)})

你将得到一个“undifined”的返回值。现在,让我们来搜索用户,有两种方式:我们可以使用我们的“users”数组,它要求用户ID;或者我们可以调用我们的“getUsers()”函数,它将显示所有用户。

我们可以先从使用用户数组开始。我们知道它,因为它曾是我们的第一个输入,用户被分配一个为0的ID。在Truffle控制台上,写如下代码:

Users.deployed().then(function(instance){return instance.users(0);})

users(0)函数的结果

现在,如果你想得到一个用户列表,使用“getUsers()”函数,输入下列代码:

Users.deployed().then(function(instance){return instance.getUsers();})

getUsers()函数的结果

让我来回顾一下我们看到了什么、为什么会这样,然后,我们将在这里结束这篇文章。

  1. 第一行的“string 0”,实际上就是我们的用户ID。

  2. 第二行是我们的用户名称,不过是以字节的形式显示的(我知道……当我们将它与前端连接起来的时候,我们会让它变得更像人话。但如果你想验证,这里有一个在线的十六进制转换器的链接。复制粘帖单引号内的一长串数字,你就可以看到结果)。

  3. 第三行是我们为这一用户输入的分数。

本周的推送到这里就差不多了,本系列的下一篇推送会接着往下讲。

结束语

我们学到了什么?

  • 任何Dapp的后端实际上都是储存在区块链上、并与一个前端或者是用户界面联系着的。

  • 结构体(struct)是一种数据类型,用于代表具有多种潜在不同类型性质的实体。

  • 在建立Dapp的时候,字符串可以是任意长度,但这在Solidity中会成为一个问题,所以我们必须将字符串转成一个固定的长度,工具是bytes32。

  • 一个成功迁移的合约会在Truffle上给你提供一个ABI(应用二进制接口)以及合约地址。

  • 虽然有些繁琐,但你可以在Truffle上使用控制台与你的合约互动。

如果你想获得一个更深刻的理解:

  • 尝试创建一个函数来更改用户名。

  • 使用Truffle控制台查看你能看到的其它信息。

要查看最新状态的代码,请检查GitHub社区上Scoreboard的最新分支post4。
加入讨论,在Twitter上关注我们: 
@Tap_Coin, Reddit,或者在Telegram上访问我们,跟我们聊聊: https://t.co/eIP47QmZ1E, 以讨论所有关于Tap项目的东西。
“靠玩家鼓劲加油,靠社区获得灵感,然后给所有人捣蛋!”

原文链接: https://medium.com/@tapdev/your-first-truffle-dapp-an-attempt-at-a-beginners-guide-to-the-truffle-framework-part-4-e6ecb0944c21
作者: Hugh Knight
翻译&校对: 阿剑 & Elisa


更多文章:

观点| 关于区块链的二三感想

观点| 关于区块链的二三感想?(二)

干货| 什么是以太坊大都会:终极指南

干货| 以太坊的工作原理

传送门| 这里有一个与V神对话的机会,请查阅

干货 | 雷电问答

区块链是什么——太长不看版

教程 | 雷电网络开发预览版 - 初体验

雷电网络:愿景,挑战与路线

记录 | 以太坊协议的发展史

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存