三.用Truffle框架开发部署合约

1.Truffle的使用
1.1 Truffle介绍

truffle是专门为合约开发设计的框架,它可以很方便的编译,部署,测试合约。

你不必再去remix平台,编译,然后复制ABI,手动来做这些繁琐的事情,基本上一个命令就解决。

1.2 安装Truffle

我们使用npm命令就能安装,如下:

npm install -g truffle

然后输入

truffle -v

出现版本号则表示安装成功:

1.3 创建truffle项目 

然后我们新建一个truffle1文件夹,命令行进入该文件夹,输入

truffle init

创建一个空的truffle项目。

然后就会在该目录下生成三个文件夹,contracts,migrations,test。

还有一个truffle-config.js文件,如下:

2.Truffle部署调用合约
2.1 编译部署合约

接着我们用vscode打开truffle1文件,(vscode是我的代码编辑器,推荐使用,当然你也可以用别的)

我们的合约代码要写在contracts里,就是sol结尾的文件(记住这个合约代码是存储在contracts里)

在contracts文件下新建Storage.sol 代码如下:

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.8.2 <0.9.0;

/**
 * @title Storage
 * @dev Store & retrieve value in a variable
 * @custom:dev-run-script ./scripts/deploy_with_ethers.ts
 */
contract Storage {

    uint256 number;

    /**
     * @dev Store value in variable
     * @param num value to store
     */
    function store(uint256 num) public {
        number = num;
    }

    /**
     * @dev Return value 
     * @return value of 'number'
     */
    function retrieve() public view returns (uint256){
        return number;
    }
}

基本上就是把remix在线平台的代码复制过来。

然后在migration文件下1_initial_migration.js  代码如下:

const Storage = artifacts.require("./Storage.sol");

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

在migration文件夹里的代码是跟合约部署有关,告诉truffle部署什么合约。

这个代码是加载我的storage.sol,然后deploy storage给外部调用。

这样我们输入truffle命令时,就会正常的部署我的合约了。

PS:注意文件名的前缀数字编号1_initial_migration.js,它告诉truffle按顺序部署(存在多个的情况下)。并且部署过后。再输入部署命令不会再次部署,你需要再创建一个2_开头的,然后后面字符可以随便自己设定。或者命令带上参数加上编号强制重新部署,如truffle migrate -f 1。

好,最后一步,是告诉truffle 部署到哪,你是要部署到ganache还是其它链。

我们这里部署到本地ganache链,打开truffle-config.js 

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

将上面这段代码注释取消,并更改端口为7545,对应我们的ganache端口。

一切准备就绪后。

我们输入truffle compile 命令编译合约:

OK,编译成功,然后会生成一个bulid文件夹,然后生成一个Storage.json文件里面有我们合约的ABI等信息:

编译成功后,我们来进行部署,输入  truffle migrate 部署合约

但是报如下错误:

这个问题跟我们第一章碰到的是一样的,solc编译的版本和ganache不兼容。

我们得改成london版的。

在truffle-config.js里添加settings: { evmVersion: 'london' } 如下:

输入truffle migrate部署OK:

上面会显示我们合约的一些信息,合约地址,部署地址,费用等。 

2.2 ganache导入truffle项目

我们创建了truffle项目部署好后,可以将这个项目导入到ganache里面,这样我们就能看到这个项目合约的一些信息,我们点击齿轮图标:

然后选择add project

选择我们项目的truffle-config.js 添加。

接着选择save and restart

然后我们点contracts就可以看到合约的一些信息了

但是导入之后,如果我们一关闭ganache,所有的一切都消失了,我们需要保存这个区块链。

点save可以保存这个区块链(在齿轮按钮旁边)。这样我们创建的账号和合约,不会因为ganache的关闭而丢失。需要时在界面加载就行,方便我们下次使用。

点了保存之后,得到项目名:

然后再次打开ganache,选择项目名打就行:

  

2.3 truffle调用合约

安装truffle后,我们在项目里输入truffle console进入控制台模式,然后可以输入代码调用测试合约。代码如下:

Storage.deployed().then(function(con) {con.store(66);})

获得合约对象con,然后调用store方法存入数字66,注意合约名是Storage。

打开ganache查看结果:

 

执行OK

如果要获取,调用retrieve()方法如下代码:

Storage.deployed().then(function(con) {con.retrieve().then(res=>{console.log(res.words[0])})})

结果:

就是给retrieve加个回调函数,res就是获得执行结果,然后res.words[0]提取出数字。

3.Truffle前端

前面我们介绍了在控制台里调用合约,现在我们要写一个前端调用,其实原理跟我们之前的前端写法是一样的,甚至你可以把之前的前端代码放到这里来依然可以。

不过为了配合Truffle使用,这里我们就用新的一种方法来实现:

3.1 webpack-dev-server安装使用

webpack之前我们已经使用过了,它可以帮我们打包静态js,那么webpack-dev-server是什么呢?

它在webpack的基础上还多了一个功能,一个小型的网页服务器,是基于nodejs(express)的。

 我们在项目里新建一个app文件夹,这个目录就放我们前端相关的代码文件。

然后命令行进入这个目录输入:

npm install webpack-dev-server 

然后目录是这样:

然后我们通过添加npm命令方式调用,打开package.json添加如下代码:

  "scripts": {
    "dev": "webpack-dev-server"
  },

然后我们命令行输入npm run dev 就会识别到scripts里的dev,然后再执行webpack-dev-server命令。(ps:如果显示webpack-dev-server不是命令,可以全局安装试试npm install webpack-dev-server -g)

此时还会安装一些依赖条件后才会启动,结果启动失败:

 那是因为我们的配置文件没弄好,将之前的webpack用的webpack.config.js配置文件复制过来,代码如下:

const path=require('path');
module.exports={
	//JavaScript执行入口文件,
	entry:'./src/main.js',
	//需要指定一下输出的路径path和输出的文件名filename
	output:{
		filename:'bundle.js',   //自定义输出文件名
		path:path.resolve(__dirname,'./dist')  //自定义输出文件所在目录
	} ,
 mode: 'development' // 设置mode
}

然后新建一个src文件夹,里面创建main.js,随便写点js代码:

 document.write('hello')

接着再运行npm run dev成功,或者你直接运行webpack-dev-server也可:

然后浏览器输入:http://localhost:8080/bundle.js

可以访问我们打包后的文件:

怎么样,运行了webpack-dev-server 后,不仅帮我们打包了js文件,还直接提供了网页服务,我们不必再像之前那样去自己写代码创建node网页服务了。

但是这里需要注意的是,webpack-dev-server跟webpack的区别,这里我们生成的目标js文件是在内存中的,并不是磁盘中真有dist这样一个目录,所以你在磁盘目录中是找不到这个bundle.js。

崦浏览器通过webpack-dev-server访问获取bundle.js,直接是从内存中获取数据。

3.2 webpack-dev-server添加index.html

但是如果我要新建一个index.html怎么访问呢?直接在app下新建一个index.html?是访问不了的。

webpack-dev-server的根目录是在public文件里,所以我们得在app下新建一个public,然后添加

index.html代码如下:

<script src="bundle.js"></script>

重启webpack-dev-server,浏览器输入localhost:8080

当然,你也可以在webpack-dev-server指定一个输出目录,用如下语句:

	devServer: {
		static: {
		  directory: path.join(__dirname, "./src"),
		},
	  },

 指定为src目录。(PS:__dirname是当前目录名。可用console.log(__dirname),node test.js执行查看)

好了,到了这一步,你知道了怎么打包,又知道了怎么输出index.html,剩下的事就简单了,基本上是把之前的前端代码复制过来就行了。

但是在这里我们还是不用老方法,我们用一些不同的方法,ABI在truffle里我们是不需要手动指定的。

还记得前面我们输入truffle compile 生成的Storage.json文件吗,这里有我们的合约信息,需要时我们直接加载就行了。

3.3 前端js代码

这里我们将第三章的main.js代码拿来进行一些修改如下:

import conInfo from "../../build/contracts/Storage.json"; //导入Storage.json合约信息
//合约abi
var abi=conInfo.abi; //获得合约ABI

//获取合约地址
var conadr=conInfo.networks['5777'].address; //这里的5777 id具体看你们的storage.json 你也可以直接填,或者通过 web3.eth.net.getId();之类的获取匹配
我这里只是演示一下方法

var Web3=require("web3");
var web3;
var accountFrom;
var myContract;

if (window.ethereum)
{
    alert('请使用未安装metamask的浏览器!');

}
else
{
    web3 = new Web3(new Web3.providers.HttpProvider("http://127.0.0.1:7545"));

    myContract=new web3.eth.Contract(  //根据abi和合约地址创建
        abi,
        conadr,
      );
  //获取第一个账号地址
    web3.eth.getAccounts().then(e => {  //异步then中获取
	accountFrom = e[0];
    }) ;
}

//更新数字函数
window.updateNum =function()  //注意这里使用window 否则会报错
{
 //获取网页input的数字
  const number = parseInt(document.getElementById("number").value);

  myContract.methods.store(number).send({from:accountFrom}, function(error, transactionHash){ //执行合约的store方法存储一个数字

	const status = document.getElementById("status");
    status.innerHTML = '更新成功:'+transactionHash;

     });
}
//获取数字函数
 window.getNum =function ()
{
    myContract.methods.retrieve().call({from: accountFrom}, function(error, result){//调用retrieve方法获得你存在区链中的那个数字

        const status = document.getElementById("status");
		status.innerHTML='数字:'+result;
  
    });
}

然后记得安装一下web3,进入app目录,输入npm install web3@1.2.4

3.4 前端index.html

跟第三章index代码差不多,只是少了自建nodejs网页服务,public下index.html代码如下:

<!doctype html> 
 <html>
 <head>
<meta charset=UTF-8>
<script src="bundle.js"></script>
 </head>
 <body>
 
 <input type="text" id="number">
 <button onclick="updateNum()">更新</button>
 <br>
 <button onclick="getNum()">获取</button>
 <br>
 <h4 id="status">请操作...</h4>
</body>
</html>
3.5 项目启动测试

然后我们进入app 输入npm run dev 运行webpack-dev-server服务

结果报错:

报了很多个 Can't resolve 'url' 之类的错误。

我们可以依次安装,提示缺少什么就npm install url这样进行安装。

也可以这样,输入npm audit fix  修复。

接着再输入npm run dev 成功运行。

然后浏览器访问localhost:8080测试(注意打开ganache)

 

ganache链上有对应的记录:

测试都OK。

 另附项目文件结构,以便大家对应创建:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bczheng1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值