solidity教程(六)前端和Web3.js


title: solidity教程(六)前端和Web3.js
tags: solidity,eth

声明:本系列教程是整理cryptozombies

https://cryptozombies.io/zh而来。


Lesson 6: 应用前端和 Web3.js
哟,你都学到这里来啦。

你真是个了不得的 CryptoZombie…

通过前五课的学习,相信你已经有了扎实的 Solidity 基础.

但是若没有一个互动界面让用户来使用,一个 DApp 就不能称之为完整。

在这一课,我们将来学习如果用一个名为 Web3.js 的库来为你的 DApp 创建一个基本的前端界面,和你的智能合约交互。

需要注意的是这个 APP 界面将使用 JavaScript 来写,并不是 Solidity。因为我们的课程专注于 Ethereum / Solidity,我们就暂时假定你已经会用HTML, JavaScript(包括 ES6 promises),以及 JQuery 写网站了。因此我们不会花时间来介绍这些技术的基础知识。

如果你还不会用 HTML/JavaScript 来写网站,你应该先去学习一下这方面的基础知识再来继续接下来的课程。

少年,准备开始了吗?

第1章: 介绍 Web3.js

完成第五课以后,我们的僵尸 DApp 的 Solidity 合约部分就完成了。现在我们来做一个基本的网页好让你的用户能玩它。 要做到这一点,我们将使用以太坊基金发布的 JavaScript 库 —— Web3.js.

什么是 Web3.js?

还记得么?以太坊网络是由节点组成的,每一个节点都包含了区块链的一份拷贝。当你想要调用一份智能合约的一个方法,你需要从其中一个节点中查找并告诉它:

  1. 智能合约的地址
  2. 你想调用的方法,以及
  3. 你想传入那个方法的参数

以太坊节点只能识别一种叫做 JSON-RPC 的语言。这种语言直接读起来并不好懂。当你你想调用一个合约的方法的时候,需要发送的查询语句将会是这样的:

// 哈……祝你写所有这样的函数调用的时候都一次通过
// 往右边拉…… ==>
{
    "jsonrpc":"2.0",
    "method":"eth_sendTransaction",
    "params":[
        {
            "from":"0xb60e8dd61c5d32be8058bb8eb970870f07233155",
            "to":"0xd46e8dd67c5d32be8058bb8eb970870f07244567",
            "gas":"0x76c0",
            "gasPrice":"0x9184e72a000",
            "value":"0x9184e72a",
            "data":"0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
        }
    ],
    "id":1
}

幸运的是 Web3.js 把这些令人讨厌的查询语句都隐藏起来了, 所以你只需要与方便易懂的 JavaScript 界面进行交互即可。

你不需要构建上面的查询语句,在你的代码中调用一个函数看起来将是这样:

CryptoZombies.methods.createRandomZombie("Vitalik Nakamoto ?")
  .send({ from: "0xb60e8dd61c5d32be8058bb8eb970870f07233155", gas: "3000000" })

我们将在接下来的几章详细解释这些语句,不过首先我们来把 Web3.js 环境搭建起来。

准备好了么?

取决于你的项目工作流程和你的爱好,你可以用一些常用工具把 Web3.js 添加进来:

// 用 NPM
npm install web3
// 用 Yarn
yarn add web3
// 用 Bower
bower install web3
// ...或者其他。

甚至,你可以从 github 直接下载压缩后的 .js 文件 然后包含到你的项目文件中:



因为我们不想让你花太多在项目环境搭建上,在本教程中我们将使用上面的 script 标签来将 Web3.js 引入。

实战演习

我们为你建立了一个HTML 项目空壳 —— index.html。假设在和 index.html 同个文件夹里有一份 web3.min.js

  1. 使用上面的 script 标签代码把 web3.js 添加进去以备接下来使用。

<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>CryptoZombies front-endtitle>
    <script language="javascript" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js">script>
    
     <script language="javascript" type="text/javascript" src="web3.min.js">script>
  head>
  <body>

  body>
html>

第2章: Web3 提供者

太棒了。现在我们的项目中有了Web3.js, 来初始化它然后和区块链对话吧。

首先我们需要 Web3 Provider .

要记住,以太坊是由共享同一份数据的相同拷贝的 节点 构成的。 在 Web3.js 里设置 Web3 的 Provider(提供者) 告诉我们的代码应该和 哪个节点 交互来处理我们的读写。这就好像在传统的 Web 应用程序中为你的 API 调用设置远程 Web 服务器的网址。

你可以运行你自己的以太坊节点来作为 Provider。 不过,有一个第三方的服务,可以让你的生活变得轻松点,让你不必为了给你的用户提供DApp而维护一个以太坊节点— Infura .

Infura

Infura 是一个服务,它维护了很多以太坊节点并提供了一个缓存层来实现高速读取。你可以用他们的 API 来免费访问这个服务。 用 Infura 作为节点提供者,你可以不用自己运营节点就能很可靠地向以太坊发送、接收信息。

你可以通过这样把 Infura 作为你的 Web3 节点提供者:

var web3 = new Web3(new Web3.providers.WebsocketProvider("wss://mainnet.infura.io/ws"));

不过,因为我们的 DApp 将被很多人使用,这些用户不单会从区块链读取信息,还会向区块链 入信息,我们需要用一个方法让用户可以用他们的私钥给事务签名。

注意: 以太坊 (以及通常意义上的 blockchains )使用一个公钥/私钥对来对给事务做数字签名。把它想成一个数字签名的异常安全的密码。这样当我修改区块链上的数据的时候,我可以用我的公钥来 证明 我就是签名的那个。但是因为没人知道我的私钥,所以没人能伪造我的事务。

加密学非常复杂,所以除非你是个专家并且的确知道自己在做什么,你最好不要在你应用的前端中管理你用户的私钥。

不过幸运的是,你并不需要,已经有可以帮你处理这件事的服务了: Metamask .

Metamask

Metamask 是 Chrome 和 Firefox 的浏览器扩展, 它能让用户安全地维护他们的以太坊账户和私钥, 并用他们的账户和使用 Web3.js 的网站互动(如果你还没用过它,你肯定会想去安装的——这样你的浏览器就能使用 Web3.js 了,然后你就可以和任何与以太坊区块链通信的网站交互了)

作为开发者,如果你想让用户从他们的浏览器里通过网站和你的DApp交互(就像我们在 CryptoZombies 游戏里一样),你肯定会想要兼容 Metamask 的。

注意: Metamask 默认使用 Infura 的服务器做为 web3 提供者。 就像我们上面做的那样。不过它还为用户提供了选择他们自己 Web3 提供者的选项。所以使用 Metamask 的 web3 提供者,你就给了用户选择权,而自己无需操心这一块。

使用 Metamask 的 web3 提供者

Metamask 把它的 web3 提供者注入到浏览器的全局 JavaScript对象 web3中。所以你的应用可以检查 web3 是否存在。若存在就使用 web3.currentProvider 作为它的提供者。

这里是一些 Metamask 提供的示例代码,用来检查用户是否安装了MetaMask,如果没有安装就告诉用户需要安装MetaMask来使用我们的应用。

window.addEventListener('load', function() {

  // 检查web3是否已经注入到(Mist/MetaMask)
  if (typeof web3 !== 'undefined') {
    // 使用 Mist/MetaMask 的提供者
    web3js = new Web3(web3.currentProvider);
  } else {
    // 处理用户没安装的情况, 比如显示一个消息
    // 告诉他们要安装 MetaMask 来使用我们的应用
  }

  // 现在你可以启动你的应用并自由访问 Web3.js:
  startApp()

})

你可以在你所有的应用中使用这段样板代码,好检查用户是否安装以及告诉用户安装 MetaMask。

注意: 除了MetaMask,你的用户也可能在使用其他他的私钥管理应用,比如 Mist 浏览器。不过,它们都实现了相同的模式来注入 web3 变量。所以我这里描述的方法对两者是通用的。

实战演习

我们在HTML文件中的 标签前面放置了一个空的 script 标签。可以把这节课的 JavaScript 代码写在里面。

  1. 把上面用来检测 MetaMask 是否安装的模板代码粘贴进来。请粘贴到以 window.addEventListener 开头的代码块中。

<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>CryptoZombies front-endtitle>
    <script language="javascript" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js">script>
    <script language="javascript" type="text/javascript" src="web3.min.js">script>
  head>
  <body>

    <script>
      // Start here
      window.addEventListener('load', function() {

	  // 检查web3是否已经注入到(Mist/MetaMask)
	  if (typeof web3 !== 'undefined') {
		// 使用 Mist/MetaMask 的提供者
		web3js = new Web3(web3.currentProvider);
	  } else {
		// 处理用户没安装的情况, 比如显示一个消息
		// 告诉他们要安装 MetaMask 来使用我们的应用
	  }

	  // 现在你可以启动你的应用并自由访问 Web3.js:
	  startApp()

	})
    script>
  body>
html>

第3章: 和合约对话

现在,我们已经用 MetaMask 的 Web3 提供者初始化了 Web3.js。接下来就让它和我们的智能合约对话吧。

Web3.js 需要两个东西来和你的合约对话: 它的 地址 和它的 ABI

合约地址

在你写完了你的智能合约后,你需要编译它并把它部署到以太坊。我们将在下一课中详述部署,因为它和写代码是截然不同的过程,所以我们决定打乱顺序,先来讲 Web3.js。

在你部署智能合约以后,它将获得一个以太坊上的永久地址。如果你还记得第二课,CryptoKitties 在以太坊上的地址是 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d

你需要在部署后复制这个地址以来和你的智能合约对话。

合约 ABI

另一个 Web3.js 为了要和你的智能合约对话而需要的东西是 ABI

ABI 意为应用二进制接口(Application Binary Interface)。 基本上,它是以 JSON 格式表示合约的方法,告诉 Web3.js 如何以合同理解的方式格式化函数调用。

当你编译你的合约向以太坊部署时(我们将在第七课详述), Solidity 编译器会给你 ABI,所以除了合约地址,你还需要把这个也复制下来。

因为我们这一课不会讲述部署,所以现在我们已经帮你编译了 ABI 并放在了名为cryptozombies_abi.js,文件中,保存在一个名为 cryptoZombiesABI 的变量中。

如果我们将cryptozombies_abi.js 包含进我们的项目,我们就能通过那个变量访问 CryptoZombies ABI 。

实例化 Web3.js

一旦你有了合约的地址和 ABI,你可以像这样来实例化 Web3.js。

// 实例化 myContract
var myContract = new web3js.eth.Contract(myABI, myContractAddress);

实战演习

  1. 在文件的 标签块中,用 script 标签引入cryptozombies_abi.js,好把 ABI 的定义引入项目。

  2. 里的

你可能感兴趣的:(区块链,#,solidity教程,#,以太坊)