HOME/Articles/

如何将智能合约发布到不同的网络?

Article Outline

如何将智能合约发布到不同的网络?

环境准备

安装MetaMask

MetaMask是一个Google插件,封装了常用的Web3.js库,为用户提供更便利的区块链网络的访问途径。

安装教程参考此处

安装Geth

根据这篇教程正常安装并启动Geth,使得我们能够访问以太坊的测试网络goerli。

出现以下提示表明Geth在不断同步中导入最新区块,如图所示,正在导入6,909,257的区块。

image-20220519093932611

安装Truffle

参考这篇教程安装5.3.0版本的truffle,安装好后的开发版本应该如下。

barry@192 greeter % truffle version
Truffle v5.3.0 (core: 5.3.0)
Solidity - 0.5.8 (solc-js)
Node v12.8.0
Web3.js v1.2.9

安装Ganach

Ganach是一个开发工具,可以使用它在在本地启动一个全新的区块链网络,便于进行开发、测试。到官网下载安装即可。

案例简介

参考书籍《Hands-On Smart Contract Development with Solidity and Ethereum》中第3、4、5节的内容,以其中greeter项目为例子,实践如何完整地发布一个Dapp到以太坊不同的测试网络。

github仓库地址:https://github.com/Barryonion/greeter

后端代码

后端代码结构如下

barry@192 greeter % tree
├── contracts
│   ├── Greeter.sol
│   └── Migrations.sol
├── migrations
│   ├── 1_initial_migration.js
│   └── 2_deploy_greeter.js
├── package-lock.json
├── test
│   └── greeter_test.js
└── truffle-config.js

这是一个标准的truffle框架结构

合约代码

contracts目录中新建Greeter.sol,其内容如下

pragma solidity >= 0.4.0 < 0.7.0;

import "openzeppelin-solidity/contracts/ownership/Ownable.sol";

contract Greeter is Ownable {
  string private _greeting = "Hello, World!";

  function greet() external view returns(string memory) {
    return _greeting;
  }

  function setGreeting(string calldata greeting) external onlyOwner {
    _greeting = greeting;
  }
}

部署代码

migrations目录中新建2_deploy_greeter.js,其内容如下

const GreeterContract = artifacts.require("Greeter");

module.exports = function(deployer) {
    deployer.deploy(GreeterContract);
}

测试代码

test目录中包含测试代码。测试代码内容参考该链接,因为测试代码中除了最终版的测试用例以外,还包含了中间不断优化过程中各个版本的代码测试用例,代码较多所有就不贴到此处了,可以参考GitHub链接greeter_test.js

truffle项目配置

truffle-config.js文件是这个truffle项目的配置文件。关于配置文件的详细配置可参考这篇文档

const HDWallterProvider = require("truffle-hdwallet-provider");

module.exports = {
  contracts_build_directory: "./client/src/contracts",

  networks: {
    development: {
     host: "127.0.0.1",     // Localhost (default: none)
     port: 7545,            // Standard Ethereum port (default: none)
     network_id: "*",       // Any network (default: none)
    },

    goerli: {
      provider: () => {
        const mnemonic = process.env["MNEMONIC"]
        return new HDWallterProvider(mnemonic, "http://127.0.0.1:8545");
      },
      network_id: "*",
    },

    rinkeby: {
      networkCheckTimeout: 10000, 
      provider: () => {
        const mnemonic = process.env["MNEMONIC"]
        const project_id = process.env["INFURA_PROJECT_ID"]
        return new HDWallterProvider(
          mnemonic,
          `https://rinkeby.infura.io/v3/${project_id}`
        );
      },
      network_id: "*"
    }
  },
  // Configure your compilers
  compilers: {
    solc: {
      version: "0.5.8"      // Fetch exact version from solc-bin (default: truffle's version)
    }
  },
};

development代表本地开发网络,goerlirinkeby分别代表两个不同的测试网络。

以上几个部分构成了整个项目的后端代码。

前端代码

前端代码位于client目录下,如何运行参考README即可。

小结

以上只是呈现了最终版本的代码经过我实践后的运行效果,建议去阅读书籍,进一步了解代码编写过程中遇到的问题和改善,不断调整,会有更深刻的理解。

部署

再介绍了代码后,我们需要把合约部署到不同的网络。

本地Ganache

安装并运行起来Ganache,然后点击右侧按钮NEW WORKSPACE,添加下图所示配置信息

image-20220519104418284

再点击ADD PROJECT按钮添加项目。完毕后得到下图所示界面,表明已经在本地成功启动网络。

image-20220519104621718

执行命令truffle migrate --network development,将合约发布到本地网络,得到如下结果。

image-20220519105436373

ganache上也记录了区块的交易信息

image-20220519105637727

Goerli网络

类似的,执行truffle migrate --network goerli命令,将合约发布到网络,

image-20220518232438056

发布的交易链接在此

Rinkeby网络

类似,执行命令truffle migrate --network rinkeby,发布到rinkeby网络,发布成功后的交易链接在此

注释:发布合约到测试网络时,需要申请一些以太币。可以从以下网站申请,具体申请方式参考网站说明。

https://goerli-faucet.pk910.de/

https://faucet.goerli.starknet.io/

https://goerlifaucet.com/

交互

将合约发布到测试网络后,我们看一下如何与它进行交互

首先,把前端项目运行起来

cd client
nohup npm run start & //后台运行
cd - //回到greeter根目录

成功运行起来后应该得到如下图所示的界面。

image-20220519000139644

接下来,我们发出一条交易,交易内容为Hello,Barry。点击交易按钮,会弹出交易详情,包含预估的汽油费等信息,随后点击确认按钮。

image-20220519000358706

等待一会儿,点击MetaTask的Activity,查看最近发出的Set Greeting交易详情

image-20220519000504893

在详情页面,点击右上角View on block explorer,进入block explorer的交易详情查看页面。

image-20220519000547490

具体的交易详情可通过此链接查看。可以看到右下角的交易信息的具体内容。

image-20220519000710221

总结

本文先简要介绍了开发智能合约的必备工具,随后回顾了如何用truffle来开发一个项目,并且把该项目发布到不同的测试环境。本文内容参考书籍《Hands-On Smart Contract Development with Solidity and Ethereum》根据实际的网络环境和依赖包的版本演化做了适当的调整。调整如下:

  • 以太坊客户端没有使用书籍中介绍的parity,改用geth,parity的github仓库已经归档,官方主推geth。
  • 由于网络不通畅,建立rinkeby的网络连接时添加networkCheckTimeout参数,参考stackoverflow帖子
  • 升级了原书作者使用的truffle版本,从5.0.3升级到5.3.0,为了解决这个部署失败的问题

参考资料:

https://geth.ethereum.org/docs/getting-started

https://www.amazon.com/Hands-Contract-Development-Solidity-Ethereum/dp/1492045268/

http://bailiyingfeng.cn/2022/05/08/truffle-installation-process-pit-stop-record/

https://ethereum.stackexchange.com/questions/82688/timeout-error-on-deploying-to-rinkeby-from-truffle-migrate?newreg=9b4ef0d0fd954f95878f28c0f1f9cbbd

https://ethereum.stackexchange.com/questions/94418/deployment-failed-migrations-only-replay-protected-eip-155-transactions

https://goerli-faucet.pk910.de/

https://faucet.goerli.starknet.io/

https://goerlifaucet.com/