以太坊Dapp 编译脚本 + 部署脚本 + 测试脚本

目录

目录结构

创建包管理

安装依赖

编译脚本

安装依赖

准备合约源码

准备编译脚本

执行编译脚本

部署脚本 

安装依赖

准备部署脚本

执行部署脚本 

测试脚本

安装依赖

准备测试脚本

执行测试脚本

测试例子

 测试脚本

执行测试脚本 

将以上工作流步骤串起来

修改 package.json  

 执行命令


目录结构

手动创建 contract_workflow 文件夹

并在其目录下创建 compiled、contracts、scripts、test 四个文件夹

  • contracts 存放源代码
  • scripts 存放编译脚本
  • compiled 存放编译结果
  • test 存放测试文件

创建包管理

在 contract_workflow 目录下,执行以下命令

会生成 package.json 文件

npm init

安装依赖

在 contract_workflow 路径下,执行以下命令

安装ganache-cli,附加生成 node_modules 和 package-lock.json 文件

npm install ganache-cli@6.1.8 --save-dev

ganache-cli 仅仅用作测试用,每一次重新运行都会重新生成10个新的账号

运行 ganache-cli 后面用作测试用

./node_modules/.bin/ganache-cli

编译脚本

安装依赖

在 contract_workflow 路径下,执行以下命令

npm install solc@0.4.25

准备合约源码

contracts 目录下 新建合约 Voting.sol

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.4.25 <0.9.0;

contract Voting{
    bytes32[] public candidateList;
    mapping(bytes32 => uint8) public votesReceived;
    constructor(bytes32[] memory candidateListName) public{
        candidateList = candidateListName;
    }

    function validateCandidate(bytes32 candidateName) internal view returns(bool){
        for (uint8 i = 0; i < candidateList.length; i++){
            if(candidateName == candidateList[i]){
                return true;
            }
        }
        return false;
    }

    function vote(bytes32 candidateName) public{
        require(validateCandidate(candidateName));
        votesReceived[candidateName] += 1;
    }

    function totalVotesFor(bytes32 candidateName) public view returns(uint8){
        require(validateCandidate(candidateName));
        return votesReceived[candidateName];
    }
}

准备编译脚本

scripts 目录下 新建脚本 compile.js

const fs = require('fs-extra');
const solc = require('solc');
const path = require('path');

// resolve 将后面的路径拼接起来
// __dirname 表示当前目录, 两个下划线_

// 清除编译结果, 保留最新编译结果, 保障一致性
const compiledDir = path.resolve(__dirname, '../compiled');
fs.removeSync(compiledDir);
fs.ensureDirSync(compiledDir);

const contractDir = path.resolve(__dirname, '../contracts', 'Voting.sol')
// 同步读取文件
const contractSource = fs.readFileSync(contractDir,'utf-8');
let compiledResult = solc.compile(contractSource, 1);

console.log(compiledResult);

// solidity合约, 如果报错, 错误定位
if(Array.isArray(compiledResult.errors) && compiledResult.errors.length){
	throw new Error(compiledResult.errors[0])
}

// 导出编译后结果 compiledResult, 也可以使用 module.export
Object.keys(compiledResult.contracts).forEach(name=>{
	// 正则表达式取:开头之后的字符串
	let contractName = name.replace(/^:/,'');
	let filePath = path.resolve(__dirname, '../compiled', `${contractName}.json`);
	// 输出
	fs.outputJsonSync(filePath, compiledResult.contracts[name]);
	console.log("Saving json file to ",filePath);
})

执行编译脚本

在 contract_workflow 路径下,执行以下命令

node ./scripts/compile.js


部署脚本 

安装依赖

在 contract_workflow 路径下,执行以下命令

npm install web3@1.7.0

准备部署脚本

scripts 目录下 新建脚本 deploy.js

const Web3 = require('web3');
let web3;
if (typeof web3 !== 'undefined') {
	//当你之前如果使用过MetaMask钱包等时,你的provider可能已经设置好了,web3.currentProvider就是你目前的provider
	web3 = new Web3(web3.currentProvider);
} else {
	// set the provider you want from Web3.providers
	web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
}


const fs = require('fs-extra');
const path = require('path');

const contractDir = path.resolve(__dirname, '../compiled', 'Voting.json');
const {interface, bytecode} = require(contractDir);
let arguments = [[web3.utils.fromAscii('Alice'),web3.utils.fromAscii('Bob'),web3.utils.fromAscii('Cary')]]
let gas = 5000000;

(async () => {
	let accounts = await web3.eth.getAccounts();
	console.time("deploy time");
	let result = await new web3.eth.Contract(JSON.parse(interface))
				.deploy({
					data:bytecode,
					arguments:arguments
				})
				.send({
					from:accounts[0],
					gas:gas
				})
	console.timeEnd("deploy time")
	
	// 输出合约地址
	console.log("contract address: ",result.options.address);
})();

执行部署脚本 

在 contract_workflow 路径下,执行以下命令

执行前确定你的私链正在运行

node ./scripts/deploy.js

 


测试脚本

mocha 是一个 JavaScript 的测试框架

既可以在浏览器环境中运行,也可以在 node.js 环境下运行

mocha 主要特点有:

  • 既可以测试简单的 JavaScript 函数,又可以测试异步代码
  • 可以自动运行所有测试,也可以只运行特定的测试
  • 可以支持 before、after、beforeEach 和 afterEach 来编写初始化代码

安装依赖

npm install mocha@8.4.0 --save-dev

准备测试脚本

在 test 目录下,新建脚本 VotingTest.js

const assert = require('assert');
const path = require('path');
const ganache = require('ganache-cli');
const Web3 = require('web3');

const web3 = new Web3(ganache.provider());

const contractDir = path.resolve(__dirname, '../compiled', 'Voting.json');
const {interface, bytecode} = require(contractDir);
let contract;
let accounts;
let arguments = [[web3.utils.fromAscii('Alice'),web3.utils.fromAscii('Bob'),web3.utils.fromAscii('Cary')]]
let gas = 5000000;



describe('#contract',()=>{
	before(()=>{
		console.log('test start')
	})
	
	after(()=>{
		console.log('test end')
	})
	
	afterEach(()=>{
		console.log('current test completed')
	})
	
	// beforeEach:使每一次测试的环境都是干净的, 每次合约执行前都执行
	beforeEach(async()=>{
		accounts = await web3.eth.getAccounts();
		contract = await new web3.eth.Contract(JSON.parse(interface))
					.deploy({
						data:bytecode,
						arguments:arguments
					})
					.send({
						from:accounts[0],
						gas:gas
					})
		console.log('current test start')
	});
	
	it('deployed contract successfully',()=>{
		assert.ok(contract.options.address);
	})
	it('should be able to check the number of votes',async()=>{
		let aVoter = web3.utils.fromAscii('Alice');
		assert.ok(contract.methods.totalVotesFor(aVoter).call({from:accounts[0]}));
	})
	it('should be able to vote',async()=>{
		let voteTo = web3.utils.fromAscii('Bob')
		let BeforeNumOfVote = parseInt(await contract.methods.totalVotesFor(voteTo).call({from:accounts[0]}));
		await contract.methods.vote(voteTo).send({from:accounts[0]});
		let AfterNumOfVote = parseInt(await contract.methods.totalVotesFor(voteTo).call({from:accounts[0]}));
		assert.equal(BeforeNumOfVote + 1,AfterNumOfVote);
	})
})

执行测试脚本

在 test 目录下执行,以下命令

../node_modules/mocha/bin/mocha VotingTest.js

测试例子

 测试脚本

在 test 下创建 sum.js 和 testSum.js

执行测试脚本 

在 contract_workflow 目录下,执行以下命令 

mocha 会自动寻找目录下叫 test 的文件夹,并执行其中 所有的 js 文件

./node_modules/mocha/bin/mocha

在 test 目录下,执行以下命令

测试特定的  js 文件 或 文件夹

../node_modules/mocha/bin/mocha testSum.js


将以上工作流步骤串起来

 参考链接:

npm scripts 使用指南 - 阮一峰的网络日志https://www.ruanyifeng.com/blog/2016/10/npm_scripts.html

修改 package.json  

我们可以通过 npm script 机制,将这些智能合约的工作流串起来

修改 package.json 如下图

 ./node_modules/mocha/bin/ 可以省略 ,因为npm scripts 在执行是将./node_modules/中的包暂时加入了环境变量中

  "scripts": {
    "compile": "node scripts/compile.js",
    "predeploy": "npm run compile",
    "deploy": "node scripts/deploy.js",
    "pretest": "npm run compile",
    "test": "mocha test/"
  },

 执行命令

npm run test

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【技术背景】区块链,是一个分布式的共享账本和数据库,具有去中心化、不可篡改、可追溯、公开透明等特点。区块链技术作为科技创新的代表和未来技术的发展方向,已经上升至国家战略高度。它将为解决信息不对称问题、创造信任与合作机制等提供丰富的应用空间,也会是未来我们技术自主创新、引领产业变革的重要突破口。比特币被认为是区块链技术1.0版的应用,主要实现的是电子现金的分布式记账转账功能。而随着技术的不断发展更新,越来越多的人希望突破“账本”的限制,从而可以把这项未来技术应用在更广阔的领域。以太坊(Ethereum)为代表的第二代区块链公链项目,就是其中的佼佼者。与比特币不同,以太坊的定位是一个“世界计算机”。以区块链作为底层存储技术,我们不仅可以记账转账,而且可以构建“智能合约”(smart contract)定义程序化的处理流程,进而实现区块链上运行的“去中心化应用”(DApp)。以太坊项目自提出后就受到了广泛关注,快速的发展和壮大,而且由于其“分布式应用平台”而非“分布式账本”的定位,越来越多的开发人员开始以以太坊为基础设施,在上面开发DApp。随着更多开发人员的参与,和项目的逐步落地,以太坊已成为从事区块链学习和开发不可或缺的一个环节;既了解区块链底层原理、又熟悉以太坊架构、还能基于以太坊开发DApp的专业人才,也成为了各大公司发力区块链技术储备的重点对象。【课程简介】本套以太坊课程,对以太坊基础理论知识和架构做了系统的梳理和深入的阐述,并对solidity和DApp的开发做了系统讲解,另外还对以太坊白皮书、黄皮书做了介绍;为有志于学习区块链技术、了解以太坊底层架构和DApp开发原理的工程师提供学习平台和帮助。本教程内容主要分为五大部分:以太坊基础、以太坊原理和架构、以太坊编程及应用、合约工作流以及原理深入分析。通过学习本套课程,可以使学习者对以太坊有充分的认识,对整个区块链技术有更深刻的理解,对区块链应用开发有更加整体的领悟。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值