教程 | 以太坊开发演练,Part-5:开发 Dapp

Ajian   |     |   4087 次阅读


以太坊开发演练系列:

Part-1:智能合约
Part-2:Truffle,Ganache,Geth 和 Mist
Part-3:安全性、限制性以及一些顾虑
Part-4:代币与 ERC


1.png

如果你已经看过这个系列教程中的每一篇文章,那么你应该知道怎么在以太坊上开发 Dapp 了,在本部分中,我将告诉你如何把之前学到的知识整合起来并付诸实践。

基于以太坊的 Dapp 是一个与部署在区块链上的智能合约交互的 web 应用 。你可以使用 python 或者其他编程语言来进行这样的交互,但是本篇教程将不会涵盖其他语言的内容。本教程只着眼于使用 JavaScript 来进行交互。

我们在第一部分中介绍了如何编写智能合约,并且在第二部分中介绍了部署智能合约的方法。本教程需要你具备一定的 JavaScript 基础,但不需要你有多精通 JavaScript ,用哪种框架也都没关系,我们只会使用纯原生的 JavaScript,外加一点点让工作变得更简单的 JQuery 知识。

我们当然需要一个工具来和智能合约进行交互,下文将使用一个非常优秀的 API —— Web3.js 来完成这一工作。

本系列教程的读者其实不应该对 Web3.js 陌生,因为不仅第二部分介绍 Truffle 控制台时我们提到了它,第三部分对合约进行测试的过程中我们也使用了它。

我们开始吧

为项目新建一个文件夹,然后运行 truffle init 命令来初始化。

接着创建一个名为 “src” 的文件夹,我们会把 web 端应用的文件存储在其中。在 “src” 文件夹里新建一个 “index.html” 文件,并粘贴以下的代码到文件中:


<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Wrestling DApp</title>
  </head>
  <body>
    <h1 class="text-center">Wrestling DApp</h1>
    <hr/>


    <!-- ... -->


    <!-- JQuery will help us extract data from json files -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <!-- Web3.js will help us interact with the deployed smart contract -->
    <script src="JShelpers/web3.min.js"></script>
    <!-- Truffle contract  will our life easier when interacting with smart contracts -->
    <script src="JShelpers/truffle-contract.js"></script>
    <!-- app.js is where we will write our JS logic -->
    <script src="app.js"></script>
  </body>
</html>

创建一个名为 “JShelpers” 的文件夹,并在该目录下创建如下三个文件:

touch jquery.min.js 
touch truffle-contract.js 
touch web3.min.js

你可以在本教程的的 Github 下查看以上三个文件的源代码。

接下来回到 “src” 文件夹下,新建一个名为 “app.js” 的文件。“app.js” 文件会保存你的 JS 逻辑,在本文中我们只用到一点点 JQuery 和简单的 Javascript 来保证项目尽可能简洁,而在实际 DApp 开发中,你当然可以使用诸如 React、Angular 或是 Vue 等等顺手的框架来进行开发。

现在打开 “app.js” 文件,并将如下代码加入其中:

var web3Provider = null;
var WrestlingContract;
const nullAddress = "0x0000000000000000000000000000000000000000";

function init() {
  // We init web3 so we have access to the blockchain
  initWeb3();
}

function initWeb3() {
  if (typeof web3 !== 'undefined' && typeof web3.currentProvider !== 'undefined') {
    web3Provider = web3.currentProvider;
    web3 = new Web3(web3Provider);
  } else {    
    console.error('No web3 provider found. Please install Metamask on your browser.');
    alert('No web3 provider found. Please install Metamask on your browser.');
  }

  // we init The Wrestling contract infos so we can interact with it
  initWrestlingContract();
}

最开始要做的工作当然是创建一些必要的变量,并初始化 Web3 provider 变量。我们默认用户在使用 Dapp 时会保持运行一个 web3 provider。当前大多数用户是通过装载了 “Metamask” 插件的 Chrome 或者 Firefox 浏览器来和以太坊区块链进行交互的,所以我们可以默认 Metamask 会在网页中加载一个 web3 实例,当然如果没有检测到 Metamask 的话,则提示用户安装该插件。

现在来加入与合约进行交互所必要的函数,首先我们要对所部署的合约初始化一个引用,即创建函数 “initWrestlingContract()”:

function initWrestlingContract () {
  $.getJSON('Wrestling.json', function(data) {
    // Get the necessary contract artifact file and instantiate it with truffle-contract
    WrestlingContract = TruffleContract(data);

    // Set the provider for our contract
    WrestlingContract.setProvider(web3Provider);

    // listen to the events emitted by our smart contract
    getEvents ();

    // We'll retrieve the Wrestlers addresses set in our contract using Web3.js
    getFirstWrestlerAddress();
    getSecondWrestlerAddress();
  });
}

接着在主体部分创建其他用于接受数据的函数:

function getEvents () {
  WrestlingContract.deployed().then(function(instance) {
  var events = instance.allEvents(function(error, log){
    if (!error)
      $("#eventsList").prepend('<li>' + log.event + '</li>'); // Using JQuery, we will add new events to a list in our index.html
  });
  }).catch(function(err) {
    console.log(err.message);
  });
}

function getFirstWrestlerAddress() {
  WrestlingContract.deployed().then(function(instance) {
    return instance.wrestler1.call();
  }).then(function(result) {
    $("#wrestler1").text(result); // Using JQuery again, we will modify the html tag with id wrestler1 with the returned text from our call on the instance of the wrestling contract we deployed
  }).catch(function(err) {
    console.log(err.message);
  });
}

function getSecondWrestlerAddress() {
  WrestlingContract.deployed().then(function(instance) {
    return instance.wrestler2.call();
  }).then(function(result) {
    if(result != nullAddress) {
      $("#wrestler2").text(result);
      $("#registerToFight").remove(); // By clicking on the button with the ID registerToFight, a user can register as second wrestler, so we need to remove the button if a second wrestler is set 
    } else {
      $("#wrestler2").text("Undecided, you can register to wrestle in this event!");
    }   
  }).catch(function(err) {
    console.log(err.message);
  });
}

这些函数的 “init()” 初始化当然不会是自动的,所以我们需要手动进行触发:

// When the page loads, this will call the init() function
$(function() {
  $(window).load(function() {
    init();
  });
});

现在我们需要完成 html 页面,把它修改成如下的样子:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Wrestling DApp</title>
  </head>
  <body>
    <h1 class="text-center">Wrestling DApp</h1>
    <hr/>

    <div style="text-align: center;">
      <h3>Today's wrestling event</h3>
      <h3><span id="wrestler1"></span> <span style="color: red">VERSUS</span> <span id="wrestler2"></span></h3>

      <button id="registerToFight" onclick="registerAsSecondWrestler()">REGISTER TO FIGHT</button>
    </div>

    <div>
      <ul id="eventsList">
        <!-- Events will appear here from app.js -->
      </ul>
    </div>


    <!-- JQuery will help us extract data from json files -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <!-- Web3.js will help us interact with the deployed smart contract -->
    <script src="JShelpers/web3.min.js"></script>
    <!-- Truffle contract  will our life easier when interacting with smart contracts -->
    <script src="JShelpers/truffle-contract.js"></script>
    <!-- app.js is where we will write our JS logic -->
    <script src="app.js"></script>
  </body>
</html>

回到 “app.js” 脚本中,添加允许用户注册成为第二个 Wrestler 玩家的 “registerAsSecondWrestler” 函数:

function registerAsSecondWrestler () {
  web3.eth.getAccounts(function(error, accounts) {
  if (error) {
    console.log(error);
  } else {
    if(accounts.length <= 0) {
      alert("No account is unlocked, please authorize an account on Metamask.")
    } else {
      WrestlingContract.deployed().then(function(instance) {
        return instance.registerAsAnOpponent({from: accounts[0]});
      }).then(function(result) {
        console.log('Registered as an opponent')
        getSecondWrestlerAddress();
      }).catch(function(err) {
        console.log(err.message);
      });
    }
  }
  });
}

至此我们的 web 应用程序就完成了!现在需要来进行一些配置,加把劲好好干哦。

安装

虽然 html 文件能直接在浏览器中打开,但由于浏览器安全策略的原因,Metamask 插件不能直接与其进行交互,所以我们需要使用一个小型的本地 http 服务器来为文件提供服务。为了解决这一问题,我们将采用 lite-server :

npm init -y
npm install lite-server --save-dev

在项目的根目录下为 lite-server 创建一个名为 “bs-config.json” 的配置文件,然后将以下内容粘贴进去:

{
  "server": {
    "baseDir": ["./src", "./build/contracts"]
  }
}

以上内容会引导 lite-server 从我们 web 应用程序所在的 “src” 目录下读取文件,并且从 “./build/contracts” 目录下中读取描述了 truffle 进行智能合约部署的 json 文件。

接着加入这一行:

"dev": "lite-server",

进入 “package.json” 中的 “scripts” 节点下:

...
  "scripts": {
    "dev": "lite-server",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
...

接着在控制台中运行如下的命令,它会在浏览器中打开 “http://localhost:3000/” :

npm run dev

现在让我们搜索并在浏览器上安装 Metamask

智能合约

别忘了在你的测试网络上部署一个智能合约。你可以在本教程中的第一部分找到角力合约,并且在第二部分找到一个方法来测试。

在这一部分中,我将使用具备图形化界面版本的 Gancache ,不过当然你可以用 ganache-cli 来模拟以太坊区块链。

运行以下的 truffle 迁移指令来部署智能合约:

truffle migrate --network development

别忘了检查你的 “truffle-config.js” 文件有没有设置正确。并且检查是否加入了部署合约所必要的迁移脚本

配置 Metamask

安装好 Metamask 之后,点击那个小狐狸的标志,然后点击左上角的弹出式下拉菜单,你会看到不同的接入网络,选择 “http://127.0.0.1:7545” 。如果在弹出的下拉菜单中没有那个选项,则点击 “Custom RPC” 选项,然后加入这个链接,使得 Metamask 可以连接上 Ganache 。

现在回到 Metamsk 主界面,点击 “restore from seed phrase” ,将 ganache 中产生的12个记忆词复制粘贴到 Wallet Seed 中,然后在下面一栏中输入你自定义的密码。

2.png

这一步会解锁你的第一个账户,我们之前用该账户部署了智能合约。但是为了更好的模拟,我们会使用由 Ganache 生成的第二个账户,因此接下来点击 Metamask 右上角的用户图标,然后选择 “import account” ,粘贴你从 ganache-cli 中拷贝得来的私钥,如果你是使用有图形界面版本的 Ganache ,则点击钥匙图标进行操作。

3.png

测试 DApp

目前智能合约已经部署到了你的测试网络上, web 应用已经准备好,并且 Metamask 已经配置好了,万事俱备,接下来我们可以测试 DApp 了。

首先打开 http://localhost:3000/ ,这是 lite-server 为我们web应用提供服务的链接,你将看到下图所示的 web 应用接口:

4.png

-我们 DApp 中绝赞的UI -

确保当前 Metamask 中选定的是账号2,点击 “Register to fight” 按钮,通常 Metamask 会弹窗,提示你确认转账(如果没有弹窗,你可以通过点击小狐狸图标来进行操作)。

5.png

当点击提交按钮时,第二个 wrestler 的地址应该会自动替换成触发这次调用的账户地址(如果没有自动替换,可以刷新页面。如果转账失败,检查你是否正确地按照教程进行操作,或者 Metamask 有没有报错,因为当我写这一篇教程的时候 Metamask 的确出问题了。当前许多与以太坊相关的工具都仍处于开发阶段,我们应当对其背后付出巨大努力的开发者抱有感谢)。

以上就是一个基于以太坊的 DApp 的全貌了,在此之上再也不需要添加别的东西了。对于那些想要在 DApp 的后端来与智能合约交互的开发者来说,他们可以利用 NPM 安装基于 Node.js 的 Web3.js 库,并使用 Geth 或是 infura.io 作为 provider 来进行开发。这里就有一篇使用这种思路进行开发的优秀教程

以下是指向本教程源代码的链接:

devzl/ethereum-walkthrough-5

如果你觉得理解本教程有一定难度,你可以尝试换着阅读这一篇教程,或者这一篇

提高

现在你已经熟悉了所有开发以太坊智能合约和 DApp 的工具和方法,接下来你可以阅读其他之前尚未弄清楚的教程,阅读本文项目中提到的开发工具的文档,并且付诸实践。对阅读完整个系列教程的你来说,完成文本中提到的 web app 并且向智能合约中加入其他的方法会是再好不过的练习了。

你可以加入 Reddit 上的开发社区,在里面经常会看到有趣的开发新闻。浏览 WeekInEthereum 能让你了解到每周以太坊世界中发生了什么。 ethereum forums 也是一个十分有趣的网站,而在以太坊的 gitter 上常常能看到激烈的讨论

至此本系列教程已经介绍完毕了,但我早已准备好了一切来编写下一篇教程。点关注不迷路,下一篇教程放送的时候会通知你哦。

你也可以在推特 @dev_zl 上找到我。


原文链接: https://hackernoon.com/ethereum-development-walkthrough-part-5-making-a-dapp-4c2a3bbcd5e5
作者: dev_zl
翻译&校对: 安仔 & Elisa

本文由作者授权 EthFans 翻译及再出版。

 
0 人喜欢