我们脱离remix环境,或者说对remix的工作原理自己实现,对智能合约进行手动编译,测试,部署,调用,彻底理解remix背后工作的原理。
项目的结构如图
contracts存放合约源码
test存放合约测试文件
compile.js是合约编译文件
deploy是合约部署文件
package.json内容如下:
{
"name": "inbox",
"version": "1.0.0",
"description": "",
"main": "compile.js",
"directories": {
"test": "test"
},
"scripts": {
"test": "mocha"
},
"author": "",
"license": "ISC",
"dependencies": {
"ganache-cli": "^6.1.6",
"mocha": "^5.2.0",
"solc": "^0.4.24",
"truffle-hdwallet-provider": "^0.0.3",
"web3": "^1.0.0-beta.35"
}
}
可以看出该项目我们使用solc进行编译,mocha进行测试,测试环境使用ganache,
真实环境则使用truffle-hdwallet-provider,交互使用web3
第一步,合约源码
pragma solidity ^0.4.17;
contract Inbox {
constructor(string _message) public{
message = _message;
}
string message;
function setMessage(string str) public {
message = str;
}
function getMessage() view public returns (string){
return message;
}
}
非常简单的业务,就是向以太坊写消息,看消息。
第二步,编译合约
const path = require('path');
const fs = require('fs');
const solc = require('solc');
const srcPath = path.resolve(__dirname, 'contracts', 'Inbox.sol');
const contractCode = fs.readFileSync(srcPath, 'utf-8');
const compile = solc.compile(contractCode, 1);
console.log("compile:", compile)
//export
module.exports = compile.contracts[':Inbox'];
核心代码 solc.compile(contractCode)
就是使用solc(remix的编译环境)对源码进行编译,最后我们将 :Inbox数据导出,后面有地方用到
第三,合约测试
我们在package.json中指定了测试框架使用mocha
我们再使用ganache提供的的测试环境
const assert = require('assert');
const ganache = require('ganache-cli');
const Web3 = require('web3');
const web3 = new Web3(ganache.provider());//测试环境
const {interface, bytecode} = require('../compile')
beforeEach(() => {
});
describe("test contract", () => {
//部署合约
it('test deploy contract', async function () {
const accounts = await web3.eth.getAccounts();
const result = await new web3.eth.Contract(JSON.parse(interface))
.deploy({
data: bytecode,
arguments: ['sun']//合约构造值
})
.send({
from: accounts[0],
gas: 1000000
});
//合约地址
console.log("address:" + result.options.address);
//调用合约方法getMessage()
let message = await result.methods.getMessage().call();
console.log("message method value:" + message);
assert.equal(message, "sun");
//调用合约方法setMessage(),注意该方法由于向以太坊写入数据,需要花费gas
await result.methods.setMessage("sungege").send({
from: accounts[0],
gas: 1000000
});
//验证getMessage的值是否写入成功
message = await result.methods.getMessage().call();
console.log("message method value:" + message);
assert.equal(message, "sungege");
});
});
测试框架跑起来只需 npm run test即可
第四步,测试通过后,部署到真实网络,假如我们部署到rinkeby网络
我们知道,在remix环境中选用injected web3时我们是通过metamask来支持部署的
metamask需要你的12个助记词以及他背后的以太坊供应商infura来和以太坊网络进行通信
这里我们选用truffle-hdwallet-provider来代替metamask的功能
使用infura需要先注册,建项目得到各个网络的endpoint,这里我们使用rinkby,因此采用相应的rinkby节点
const Web3 = require('web3');
const {interface, bytecode} = require('./compile');
const HDWalletProvider = require("truffle-hdwallet-provider");
//12个助记词
let mnemonic = "usual sentence...";
/**
* just like metamask ,use mnemonic and infura
* @type {HDWalletProvider}
*/
let provider = new HDWalletProvider(mnemonic, "https://rinkeby.infura.io/v3/2b86c426683f4a6095fd175fe931d799");
//web3的网络切换到以太坊真实网络,而不是之前的ganache了
const web3 = new Web3(provider);
deploy = async () => {
const accounts = await web3.eth.getAccounts();
const result = await new web3.eth.Contract(JSON.parse(interface))
.deploy({
data: bytecode,
arguments: ['sun']
})
.send({
from: accounts[0],
gas: '3000000'
});
console.log("address:" + result.options.address);
};
deploy();
我们只需要node deploy.js就可以部署了
部署成功后,我们会得到合约在以太坊rinkeby上的地址
根据该地址,可以索引到合约实例
在remix环境中,我们输入该地址,就可得到我们写的合约的api,进入进行交互
以上就是合约编译测试部署交互的全流程,就是remix背后的工作原理
在交互上,如果我们引入前端技术,就是一个完整的DAPP。