jjzjj

智能合约开发测试部署验证一条龙

cemcoe 2023-10-13 原文

前面提到,我最近在看 Web3,这不记录下最近看到的好玩的。

忘了在哪里看到的一句话,Web3 这个东西,刚看时让人摸不到头脑的点在于,你很难知道要用哪些东西去组装,去哪里拿数据。

比如都说区块链人人可访问,我要到哪里看到它?毕竟看得见的东西更让人心安。

给俺瞧瞧。

我到哪里去看区块链上的数据?不给你 区块链浏览器 这个关键词,大概很难知晓。

一个经常会看到的疑问是如何与合约交互,比如,合约里存了一个字符串,我现在要将其展示到页面上,如何搞?

这玩意是去中心化的呀,没有一个 API 地址让你去连呀,于是就迷茫了。。。

。。。
。。。
。。。

其实 Web3 里的很多东西,就是一张纸,没啥,与智能合约交互其实就是要和节点交互,但维护全节点也太难受了。

那么就换一种方案就是使用别人维护的节点,其实就是连接轻节点提供商,比如 MetaMask 或者 Alchemy,当然了,这里有去中心化的取舍了。

废话说完了,进入正题。


通过使用 Hardhat Alchemy Solidity 来走一下智能合约开发部署流程。

  • Hardhat 创建项目
  • 实现一个 Hello World 智能合约
  • mocha 来测试合约
  • 如何将合约部署到区块网络
  • 如何验证已经部署的合约

1. 环境搭建

前提条件,前端常用的环境 node 就不多说了。

打开 Hardhat 官网,照着文档一把梭,把它当成一个帮你创建合约项目的一个脚手架就完了。

https://hardhat.org/

注意,Hardhat 更新很快,一些教程可能不是很准确,没事看看官网文档就好了。

npx hardhat

下面是执行时终端输出:

cemcoe@cemcoe MINGW64 ~/workplace/web3gogogo/contracts (main)
$ npx hardhat
Need to install the following packages:
  hardhat
Ok to proceed? (y) y
888    888                      888 888               888
888    888                      888 888               888   
888    888                      888 888               888   
8888888888  8888b.  888d888 .d88888 88888b.   8888b.  888888
888    888     "88b 888P"  d88" 888 888 "88b     "88b 888   
888    888 .d888888 888    888  888 888  888 .d888888 888   
888    888 888  888 888    Y88b 888 888  888 888  888 Y88b. 
888    888 "Y888888 888     "Y88888 888  888 "Y888888  "Y888

Welcome to Hardhat v2.10.2

? What do you want to do? ...      
> Create a JavaScript project      
  Create a TypeScript project      
  Create an empty hardhat.config.js
  Quit

选择 Create a JavaScript project,并回车。注意,按照输出,这里还需要装点东西:

cemcoe@cemcoe MINGW64 ~/workplace/web3gogogo/contracts (main)
$ npx hardhat
Need to install the following packages:
  hardhat
Ok to proceed? (y) y
888    888                      888 888               888
888    888                      888 888               888   
888    888                      888 888               888   
8888888888  8888b.  888d888 .d88888 88888b.   8888b.  888888
888    888     "88b 888P"  d88" 888 888 "88b     "88b 888
888    888 .d888888 888    888  888 888  888 .d888888 888
888    888 888  888 888    Y88b 888 888  888 888  888 Y88b.
888    888 "Y888888 888     "Y88888 888  888 "Y888888  "Y888

Welcome to Hardhat v2.10.2

√ What do you want to do? · Create a JavaScript project
√ Hardhat project root: · C:\Users\cemcoe\workplace\web3gogogo\contracts
√ Do you want to add a .gitignore? (Y/n) · y

You need to install these dependencies to run the sample project:
  npm install --save-dev "hardhat@^2.10.2" "@nomicfoundation/hardhat-toolbox@^1.0.1"

Project created

See the README.md file for some example tasks you can run

Give Hardhat a star on Github if you're enjoying it!

     https://github.com/NomicFoundation/hardhat

听话,按照它说的做,把依赖都装上:

npm install --save-dev "hardhat@^2.10.2" "@nomicfoundation/hardhat-toolbox@^1.0.1"

基本环境就好了,可以开心写合约玩了。

2. 看下目录

哦,天呀,小宝贝,打开目录看一下吧。

目录结构

国际惯例,写个 HelloWorld 先。

到 contracts 目录下按照 Lock.sol 来画 HelloWorld,这个文件要尽可能简单,现在的重点在于合约的编译部署和验证。
合约大概长这样:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

contract HelloWorld {
    string public _string = "Hello, World! My Name is cemcoe!";
}

好了,合约不用管了,毕竟不是本文的重点。

3. 写个测试

下面为合约写个测试,不同于前端,合约的安全是重重重重点,毕竟里面存的是资产,测试就不能少了。

https://hardhat.org/hardhat-runner/docs/guides/test-contracts

这里测试是 Chai 和 Mocha 提供的能力,需要注意的是 chai 仅仅是一个assertion library,不是JavaScript test framework。

下面代码中的 describe 以及 it 并不是由 chai 提供的,所以在 chai 的官网你是找不到这俩货的,我在 chai 的官网找半天it。。。

到 test 下创建同名文件来测试一下合约,测试写完那就运行一下。

主要是下面的代码没有 mocha 的影子,但其实 Hardhat 的文档里有提到。

const {
  time,
  loadFixture,
} = require("@nomicfoundation/hardhat-network-helpers");
const { expect } = require("chai");
// chai 仅仅是一个assertion library,不是JavaScript test framework
// 下面describe以及it并不是由chai提供的,所以在chai的官网你是找不到这俩货的
// https://mochajs.org/
// 比起简单的语法,上面的认知还是蛮重要的

describe("HelloWorld", function () {
  // We define a fixture to reuse the same setup in every test.
  // We use loadFixture to run this setup once, snapshot that state,
  // and reset Hardhat Network to that snapshot in every test.
  async function deployOneYearLockFixture() {
    // Contracts are deployed using the first signer/account by default
    const [owner] = await ethers.getSigners();

    const CONTRACT = await ethers.getContractFactory("HelloWorld");
    const contract = await CONTRACT.deploy();

    return { contract, owner };
  }

  describe("Deployment", function () {
    it("Should set the right string", async function () {
      const { contract } = await loadFixture(deployOneYearLockFixture);

      expect(await contract._string()).to.equal(
        "Hello, World! My Name is cemcoe!"
      );
    });
  });
});


运行一下测试脚本

$ npx hardhat test ./test/0.HelloWorld.test.js
Compiled 3 Solidity files successfully


  HelloWorld
    Deployment
      ✔ Should set the right string (3150ms)


  1 passing (3s)

bingo,测试完成。

4. 部署到测试网络

目前为止,其实一直是关上门称王称霸,现在将合约发布到测试网络吧。

这里要找一个服务商,帮忙上链,什么,你不想要中间商,嗯,把握重点吧伙计。

到这里 https://www.alchemy.com/ 注册一个账号拿到key,并将相应信息配置到hardhat.config.js 文件中,像下面这样:

networks: {
  goerli: {
    url: GOERLI_URL,
    accounts: [PRIVATE_KEY],
  },
  polygonMumbai: {
    url: process.env.MUMBAI_URL,
    accounts: [process.env.PRIVATE_KEY],
  },
  optimismGoerli: {
    url: OPTIMISM_GOERLI_URL,
    accounts: [PRIVATE_KEY],
  },
},

当然,我这里用了一下 dotenv 来存敏感信息,为了体验编译部署流程可以直接写死在文件中。

你可以只配置一个网络,比如 polygonMumbai,其中 MUMBAI_URL 是申请的URL,而 PRIVATE_KEY 是你钱包地址的私钥,做好自己的风险控制,别把自己存有资产的钱包密钥泄露。

配置文件搞好以后就来写一个部署脚本好了。其实很简单。

const hre = require("hardhat");

async function main() {
  const CONTRACT = await hre.ethers.getContractFactory("HelloWorld");
  const contract = await CONTRACT.deploy();

  await contract.deployed();

  console.log(`contract deployed to ${contract.address}`);
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

核心代码就三句。。。

配置文件和部署脚本都写好以后就可以开始部署了。

npx hardhat run scripts/0.HelloWorld.deploy.js --network polygonMumbai
$ npx hardhat run scripts/0.HelloWorld.deploy.js --network polygonMumbai
Compiled 1 Solidity file successfully
contract deployed to 0x8487Ec50f29d1d36Cb422d6f45AA1ef38Cd2bBA2

5. 验证合约

验证合约的目的是让合约代码在区块浏览器上可读。

和部署合约类似要先写一下申请账号,再配置文件,然后运行脚本,一步一步来。

先到对应的区块浏览器去申请key,这里是 https://mumbai.polygonscan.com/

然后将key配置到hardhat.config.js文件中。

 etherscan: {
    apiKey: {
      goerli: process.env.ETHERSCAN_API_KEY,
      polygonMumbai: process.env.POLYGONSCAN_API_KEY,
      // optimismGoerli 不在默认配置中
      optimismGoerli: "abc",
    },
  },

当然了,仍然是按需配置,需要什么网络就到对应的区块浏览器去拿key再配置进去。

有了key,配置文件,再加上部署的合约的地址,就可以验证合约了。

npx hardhat verify --network polygonMumbai 0x8487Ec50f29d1d36Cb422d6f45AA1ef38Cd2bBA2

一条龙完成。


$ npx hardhat verify --network polygonMumbai 0x8487Ec50f29d1d36Cb422d6f45AA1ef38Cd2bBA2
Nothing to compile
Successfully submitted source code for contract
contracts/0.HelloWorld.sol:HelloWorld at 0x8487Ec50f29d1d36Cb422d6f45AA1ef38Cd2bBA2
for verification on the block explorer. Waiting for verification result...

Successfully verified contract HelloWorld on Etherscan.
https://mumbai.polygonscan.com/address/0x8487Ec50f29d1d36Cb422d6f45AA1ef38Cd2bBA2#code
bigo

注意, goerli 或其它网络验证合约时,因网络原因会出现 Error in plugin @nomiclabs/hardhat-etherscan: Failed to send contract verification request. 的情况。

$ npx hardhat verify --network goerli 0x7520A14646eF8d8123e88937DcB39604E8E70CeA
Nothing to compile
Error in plugin @nomiclabs/hardhat-etherscan: Failed to send contract verification request.
Endpoint URL: https://api-goerli.etherscan.io/api
Reason: Connect Timeout Error

有关智能合约开发测试部署验证一条龙的更多相关文章

  1. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  2. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  3. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  4. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  5. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  6. ruby - Ruby 的 Hash 在比较键时使用哪种相等性测试? - 2

    我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。

  7. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  8. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  9. ruby - Sinatra:运行 rspec 测试时记录噪音 - 2

    Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/

  10. ruby-on-rails - 如何将验证与模型分开 - 2

    我有一些非常大的模型,我必须将它们迁移到最新版本的Rails。这些模型有相当多的验证(User有大约50个验证)。是否可以将所有这些验证移动到另一个文件中?说app/models/validations/user_validations.rb。如果可以,有人可以提供示例吗? 最佳答案 您可以为此使用关注点:#app/models/validations/user_validations.rbrequire'active_support/concern'moduleUserValidationsextendActiveSupport:

随机推荐