策划|Tina编辑|盖磊区块链前哨导语:作为一款以区块链和以太坊为基础建立起来的游戏,“链养猫”游戏《谜恋猫》(CryptoKitties)去年 11 月发布至今,已经吸引 150 多万用户,总共完成的交易已经超过 4000 万美元。其中流行的一些小猫价值已经超过 20 万美元。而在本周,“链养猫”背后的 Axiom Zen 游戏工作室把它分拆为独立公司,并且已经获得 1200 万美元融资。

2 月 4 日晚,百度悄然上线了区块链游戏“莱茨狗”,pet-chain.baidu.com,造型和玩法上与“链养猫”如出一辙。官方介绍:“莱茨狗”的开发团队来自百度金融区块链实验室,目前的技术已应用于多条核心业务线,支撑了超 500 亿元资产的真实性问题。

针对宠物商店这一现象级游戏应用,我们给出了一个在以太坊上构建去中心化区块链应用的教程。教程中使用了 Solidity 语言和 Truffle 框架,详细说明了智能合约的编写、编译、模拟部署和测试过程,并介绍了如何使用 Truffle Box 构建应用的 UI。

大家都搞区块链,来不及解释了,赶紧上车就对了,按照这个教程自己写个宠物商店吧。

更多干货内容请关注微信公众号“区块链前哨”,(ID:blockchain-666)

基于区块链构建的去中心化应用(Dapp,Distributed application)引人关注,因为这样的应用并非集中于某个特定的管理者。

下面,我们将生成一个基本的去中心化应用,以此实际了解此类应用的机制。

遵循 Truffle 指南中提供的“以太坊宠物商店”,我将在 Web 上实际构建一个宠物商店去中心化应用。基于 Truffle 开发框架,我使用了一种称为“Solidity”的语言编写智能合约。

项目完工的效果如下图。如果用户点击了心仪宠物所对应的“adopt”按钮,应用将启动 MetaMask 检查所展示的宠物的数量和费用、创建交易并使用 ETH 支付。

我们可以看到,该应用不同于一般的电子商务网站,在购买时不必输入个人信息或信用卡信息。此外,购买数据以交易形式记录在以太坊区块链中,因此不会被篡改。

实现去中心化应用的具体流程如下:

  • 设置开发环境;

  • 使用 Truffle Box 创建 Truffle 项目;

  • 描述智能合约;

  • 编译并模拟部署(Migrating)智能合约;

  • 测试智能合约;

  • 建立附着于智能合约之上的 UI;

  • 在浏览器中使用去中心化应用。

首先准备使用 node 和 npm 的环境。对于 Ubuntu 操作系统,安装 Node.js 8.x 的操作命令为:

$ apt-get update
$ curl -sL https://deb.nodesource.com/setup_8.x | bash -
$ apt-get install -y nodejs

第一步,我们需要安装 Truffle。

$ npm install -g truffle

Truffle 是一个以太坊开发框架。对于智能合约开发,Truffle 是一种非常有用的框架,可以高效地实现源代码的编译和部署。

第二步,建立一个名为“pet-shop-tutorial”的文件夹作为工作目录。通常使用命令 truffle init 初始化工作目录,并创建一个空目录。但是在本文给出的教程中,是在一个预先准备好的项目“Truffle Box”手工中创建了这个目录:

$ mkdir pet-shop-tutorial
$ cd pet-shop-tutorial
$ truffle unbox pet-shop

第三步,在“pet-shop-tutorial”目录中建立如下图所列的文件和目录:

实际使用的目录和文件如下:

  • contracts 目录:包含描述智能合约的 Solidity 源文件;

  • migrations 目录:模拟部署(migration)系统,用于部署智能合约过程中。

  • test 目录:目录中为测试文件,使用 JavaScript 和 Solidity 编写;

  • truffle.js:Truffle 配置文件。

其中,Solidity 是一种描述以太坊智能合约的编程语言。

下面,我将使用 Solidity 编写智能合约。在所创建的 contracts 目录中,建立一个名为“Adoption.sol”的文件,文件内容如下:

下面我依次介绍代码的各个部分:

pragma solidity ^0.4.4;

该语句指定了 Solidity 编译器的版本信息。此外,Solidity 与 JavaScript 类似,需在代码行结尾处添加分号“;”。

contract Adoption { ・・・ }

这里定义了一个名为 Adoption 的合约,并在其中实现合约。

address[16] public adopters;

这句话定义了一个名为 adopters 的状态变量。鉴于 Solidity 是一种静态语言,因此变量必须要定义类型。除了 string、uint 等通用数据类型之外,Solidity 还具有一种特有的数据类型 address。address 中包含账户的地址。

这里,定义了一个名为 adopters 的 address 数组,该变量具有 16 个地址。

此外,在 adopters 变量前指定了 public,即任何人都可以访问合约。

在定义了以上变量之后,开始定义合约的方法。

function adopt(uint petId) public returns (uint) {
require(petId >= 0 && petId <= 15);
adopters[petId] = msg.sender;
return petId;
}

根据 adopters 数组的长度,将整数类型变量 petId 的值设为 0 到 15(数组的索引值从 0 开始)。

代码中使用 require() 函数设置 petId 的值为 0 到 15。

msg.sender 表示执行函数者(或智能合约)的地址。

这样,语句 adopters [petId] = msg.sender; 将执行函数者的地址添加到 adopters 数组。

返回值在 petId 中。

上面定义的 adopt() 函数返回一个地址,因为 petId 是 adopters 数组的键值。

但是,鉴于每次重加载都需要做 16 次 API 调用,我使用下面定义的 getAdopters() 函数返回整个 adopters 数组:

function getAdopters() public returns (address[16]) {
return adopters;
}

鉴于变量 adopters 已经定义,函数可以仅指定数据类型,并将返回值返回。

至此,我完成了对智能合约的描述。

总结一下,我创建了如下的 Adoption 合约:“共有 16 种宠物。如果用户想领养一只宠物,就将用户地址和该宠物 ID 绑定在一起”。

下面,我们将继续编译智能合约,并模拟部署。

编译将以编程语言编写的源代码转译为机器可直接执行的机器语言。换句话说,本例中就是将 Solidity 语言编写的代码转换为 EVM(以太坊虚拟机,Ethereum Virtual Machine)可执行的字节码。

在包含去中心化应用的目录中,使用终端等方式加载 Truffle Develop:

$ truffle develop

然后,在启动的 Truffle 开发控制台上,输入 compile 命令:

$ truffle(develop)> compile

如果输出如下,表明编译成功。

Compiling ./contracts/Adoption.sol...
Compiling ./contracts/Migrations.sol...
Writing artifacts to ./build/contracts

尽管其中可能存在一些公开可见的警告,但是继续编译是没有问题的。下面请一直保持 Truffle 开发控制台的运行。

模拟部署(Migration)类似于“移动”,就是将已有系统或类似系统迁移到一个新的平台上。

在本例中,模拟部署文件完成将所创建的 Adoption 合约部署到以太坊区块链网络上。

如果查看 migrations 目录的内容,其中已经存在一个名为“1_initial_migration.js”的 JavaScript 部署文件。该文件将 Migrations.sol 部署到 contracts 目录中,并管理它,这使得一系列的智能合约可以正确地迁移。

下面在 migrations 目录中创建一个名为“2_deploy_contracts.js”的部署文件。在部署文件中写入如下内容:

const Adoption = artifacts.require("Adoption");
module.exports = (deployer) => {
deployer.deploy(Adoption);
};

在前面打开的 Truffle 开发控制台上,运行 migrate 命令:

$ truffle(develop)> migrate

如果生成如下输出,表明模拟部署成功完成:

测试智能合约是非常重要的一步。这是因为智能合约中的设计错误和缺陷将与用户的代币(资产)直接相关,可导致对用户利益的严重损害。

智能合约测试主要分为手工测试和自动测试。下面分别介绍这两种测试。

手工测试使用 Ganache 等本地开发环境工具,检查应用的运行情况。这易于理解,因为这些工具实际指向 GUI 中的交易。

本文将跳过对手工测试的介绍。下面介绍自动测试。

在 Truffle 中,可使用 JavaScript 或 Solidity 描述智能合约的自动测试。在本例中,我采用 Solidity 编写。

在所创建的 test 目录中,创建一个名为“TestAdoption.sol”的文件,其中的内容如下:

文件内容略长。我将分解该文件做介绍。

首先,我导入了如下三个合约:

  • Assert.sol:测试期间的各种检查工作。

  • DeployedAddresses.sol:获取在测试期间部署的合约的地址。

  • Adoption.sol:测试智能合约。

创建一个名为“TestAdoption”的合约,并定义变量 adoption。adoption 包含 DeployedAddresses。

在下面给出的 TestAdoption 合约中,我定义了用于测试的函数:

function testUserCanAdoptPet() {
uint returnedId = adoption.adopt(8);
uint expected = 8;
Assert.equal(returnedId, expected, "Adoption of pet ID 8 should be recorded.");
}

该代码测试 Adoption 合约中定义的 adopt() 函数。如果 adopt() 函数功能正常,它将返回与参数具有同一数值的 petId(即返回值)。

此处将值为 8 的 petId 置入 adopt() 函数,并使用 Assert.equal() 函数确保与 petId 返回值匹配。

function testGetAdopterAddressByPetId() {
address expected = this;
address adopter = adoption.adopters(8);
Assert.equal(adopter, expected, "Owner of pet ID 8 should be recorded.");
}

需要测试的是 petId 是否关联了正确的所有者地址。代码测试了宠物 ID 是 8 的所有者的地址是否正确。

顺便提及,变量 this 表示的是当前合约的地址。

function testGetAdopterAddressByPetIdInArray() {
address expected = this;
address[16] memory adopters = adoption.getAdopters();
Assert.equal(adopters[8], expected, "Owner of pet ID 8 should be recorded.");
}

最后,检查具有所有地址的数组 adopters 是否被正确返回。

属性 memory 并未保存在合约的“存储”中,这意味着它是一个临时记录的值。

现在可以编写测试。我将使用 Truffle Develop 返回测试文件。

$ truffle(develop)> test

如果输出如下,表明测试成功。

目前为止,我们已经完成了智能合约的创建,模拟部署在本地环境的测试区块链中,并测试其是否正常工作。

下面,我们将创建用户界面,在浏览器中实际查看宠物商店。

基本结构已经由 Truffle Box 构建,我们只需在以太坊中添加特性函数。

应用的前端部分位于 src 目录中,我们需要编辑其中的 /src/js/app.js 文件。

下面给出 App 对象的声明,我随后在①到④处添加代码。

下面分别介绍在① ~ ④处添加的源代码。

① web3 实例化if (typeof web3 !== 'undefined') {
App.web3Provider = web3.currentProvider;
} else {
App.web3Provider = new Web3.providers.HttpProvider('http://localhost:9545');
}
web3 = new Web3(App.web3Provider);

首先,确保 web3 的实例是“活动”的。如果它是“活动”的,那么使用所创建应用的 web3 对象替换它。如果它并非“活动”的,那么在本地开发环境中创建 web3 对象。

② 合约实例化

鉴于我们现在可通过 web3 与“以太坊网络”建立通讯,这时需要实例化所创建的“智能合约”。为实现合约的实例化,我们需要将合约的具体位置以及工作方式告知 web3。

$.getJSON('Adoption.json', function(data) {
var AdoptionArtifact = data;
App.contracts.Adoption = TruffleContract(AdoptionArtifact);
App.contracts.Adoption.setProvider(App.web3Provider);
return App.markAdopted();
});

Truffle 提供了一个有用的软件库,称为“truffle-contract”。该软件库作用于 web3 上,简化了与“智能合约”的联系。例如,truffle-contract 实现模拟部署期间合约信息的同步,无需手工更改部署地址。

Artifact 文件提供了部署地址和 ABI(应用二进制接口,Application Binary Interface)信息。

ABI 表示了合约接口上的信息,即变量、函数、参数等。

在 TruffleContract() 函数中插入 Artifact,并实例化合约。然后设置由 web3 实例化所创建的 App.web3Provider 到合约中。

此外,如果先前已经选定了宠物,那么这时需要调用 markAdopted()。每次智能合约数据发生改变时,都有必要对 UI 进行更新。更新 UI 定义为在③处给出的各种“函数”。

③ UI 更新

下面的代码确保宠物状态保持更改,并且 UI 得到了更新。

var adoptionInstance;
 App.contracts.Adoption.deployed().then(function(instance) {
adoptionInstance = instance;
return adoptionInstance.getAdopters.call();
 }).then(function(adopters) {
for (i = 0; i < adopters.length; i++) {
if (adopters[i] !== '0x0000000000000000000000000000000000000000') {
$('.panel-pet').eq(i).find('button').text('Success').attr('disabled', true);
}
}
 }).catch(function(err) {
console.log(err.message);
 });

代码首先在所部署的 Adoption 合约实例上调用 getAdopters() 函数。call() 函数并不更改区块链的状态,它只是读取数据,因此这里无需支付 GAS。

此后,代码检查是否每个 petId 都绑定了一个地址。如果地址存在,就将按钮状态改为“Success”,这样用户不能再次按下按钮。

④ 操作 adopt() 函数var adoptionInstance;
web3.eth.getAccounts(function(error, accounts) {
if (error) {
console.log(error);
}
var account = accounts[0];
App.contracts.Adoption.deployed().then(function(instance) {
adoptionInstance = instance;
return adoptionInstance.adopt(petId, {from: account});
}).then(function(result) {
return App.markAdopted();
}).catch(function(err) {
console.log(err.message);
});
});

在本例中,确认 web3 使用账号无误后,就实际进行交易处理。交易执行通过 adopt() 函数完成,输入参数为一个包含 petId 和账号地址的对象。

之后,使用在③中定义的 markAdopted() 函数,将交易结果在 UI 上以新数据显示。

一旦万事俱备,现在就可以在浏览器中查看上面创建的去中心化应用。

这里需要预先做一些安装工作,因为我们将使用 Chorome 的一个扩展 MetaMask。账号将通过下面给出的“钱包私钥”(Wallet Seed),使用 Truffle Develop 的账号。在执行 Truffle Develop 时,会显示该私钥(它是通用私钥)。

candy maple cake sugar pudding cream honey rich smooth crumble sweet treat

如果使用 MetaMask,可以通过菜单项“Lock”访问如下的屏幕。

为了将 MetaMask 连接到 Truffle Develop 创建的区块链,要将左上位置的“Main Network”改为“Custom RPC”,“Truffle Develop”更改为“http://localhost:9545”,并将显示从“Main Network”更改为“Private Network”。

账号由上面给出的私钥生成,其中应该会具有少许的 100ETH,它们来自于合约部署中消费的 GAS 量。

一旦对 MetaMask 做了如上设置,就可以在终端等处输入下面的命令,启动本地 Web 服务器(鉴于已经 bs-config.json 和 package.json 已经创建,还可以使用 lite-server 软件库)。

$ npm run dev

这样,在浏览器中就能显示如下的去中心化应用。

一旦点击心仪宠物的“adopt”按钮,交易就通过 MetaMask 发出,使用者可以用 ETH 支付宠物购买。

鉴于本文只是给出一个教程,因此内容主要聚焦于使用 Truffle Box 在以太坊中实现的去中心化应用的一些特性。即便读者并不具备详细的以太坊区块链知识,只要能按教程实际动手操作,就可理解去中心化应用的工作机制。

原文发布时间为:2018-03-26
本文作者:分分钟变大神
本文来源:微信公众号-区块链前哨,如需转载请联系原作者。

基于以太坊的去中心化宠物商店构建教程相关推荐

  1. 基于以太坊的去中心化存储协议Swarm计划在2季度发布1.0版

    基于以太坊的去中心化存储协议Swarm表示,下一个重要里程碑Swarm 1.0版本预计在今年第二季度发布,在此之前将以约14天的间隔发布定期更新.除此之外,Swarm计划提前在以太坊Goerli测试网 ...

  2. R1 协议:基于以太坊的去中心化交易协议

    一. 简介 R1 协议是 ONEROOT 提出的基于以太坊的去中心化交易协议.R1 协议具有去中心化交易协议的基本特性,实现了链下订单中继.链上结算.交易记录可审计.去中心化资产托管.此外,R1 协议 ...

  3. 基于区块链的去中心化抗量子密钥管理系统

    摘要: 区块链技术在2008年被提出被称为比特币(我觉得应该是翻译为比特币应用了区块链技术),区块链技术是一种分布式的数据库.公钥基础设施PKI(Public Key Infrastructure)系 ...

  4. 基于区块链的去中心化存储(区块链存储)的工作流程

    引入 个人电脑上存储有限,而且如果硬盘损坏数据丢失的话,也不容易恢复.因此很多人愿意把数据上传到云盘里,也就是云存储.但是云存储是服务提供商控制的,比如阿里云,百度云等,我们称为中心化的存储 ,人们对 ...

  5. Moralis去中心化Web3应用开发教程

    Moralis去中心化Web3应用开发教程 课程英文名:Moralis Web3 dApp Programming 此视频教程共5.5小时,中英双语字幕,画质清晰无水印,源码附件全 下载地址 百度网盘 ...

  6. 【学习笔记】Mac基于truffle第一个去中心化应用(Dapp) - 宠物商店

    一.项目背景 Pete 有一个宠物店,有 16 只宠物,他想开发一个去中心化应用,让大家来领养宠物. 在 truffle box 中,已经提供了 pet-shop 的网站部分的代码,我们只需要编写合约 ...

  7. 去中心化 去区块链_基于区块链的去中心化应用的四种架构模式候选

    去中心化 去区块链 Blockchain has a diverse set of use cases, ranging from finance to a decentralized Interne ...

  8. 星际迷航(FILE)基于 IPFS 协议的去中心化游戏生态

    随着 5G 通信技术的快速发展及终端电子设备的更新迭代,网络游戏载体.类型不断丰富, 电子竞技行业的资本涌入和人才发展,游戏这项"第九艺术"的受众群体在以指数级增长的方式不断扩大, ...

  9. Drynx: 基于区块链的去中心化隐私保护机器学习系统

    该文章转载自本人的知乎专栏,有兴趣的小伙伴可以来我的专栏学习更多相关知识,包含了同态加密.安全多方计算.机器学习和联邦学习.近世代数等.下面是我的知乎文章首页,可以点专栏去查看确定方向的文章.所有相关 ...

最新文章

  1. Re-Located Record in Grid
  2. Linux基础命令的操作(时间与日期,日历,计算器)
  3. linux内核引入模块机制好处,linux内核模块的版本检查机制
  4. math.floor java_Java Math.floor() 方法
  5. 连接mysql报zone时区错误
  6. caffe 中base_lr、weight_decay、lr_mult、decay_mult代表什么意思?
  7. Micro-CMS v1
  8. ue4 无限地图_UE4大地图(流关卡、无缝地图)
  9. 餐饮水单打印软件_开发一款餐饮手机app系统软件什么价格?有哪些方面需要考虑?...
  10. linux kill 关闭进程命令
  11. sorted函数python_python中排序函数sort,sorted和operator.itemgetter的使用
  12. C语言_结构体与共用体
  13. CyclicBarrier底层实现和原理
  14. 2021全国研究生数学建模竞赛C题思路
  15. CSC联合培养加拿大工签攻略
  16. Echarts 单一柱状图显示不同颜色
  17. 如何直接修改html文件,如何修改HTML的文件?
  18. web前端之Vue——子组件的详解
  19. TreeGrid插件简练了解使用
  20. c语言编程电机星三角启动,三相异步电动机星三角减压启动控制plc编程实例

热门文章

  1. 中国涂料树脂行业投资盈利预测及发展规模展望报告2021-2027年版
  2. openresty开发系列22--lua的元表
  3. Go 变量及基本数据类型3
  4. 我也学习JAVA多线程-join
  5. mysql数据库文件的真实的物理存储位置
  6. Git学习笔记05--git stash
  7. 必要商城高级UED经理张不写:设计师如何规划职业方向
  8. 当变化来临,PM的心态和节奏如何把握?
  9. PMCAFF产品众测 | 对话随手攒CEO聊聊这款产品的设计、推广和改进(活动已结束)
  10. 一个产品新人的年终总结 PMcaff | 分享