pragma solidity ^0.4.24;
contract Adoption {
address[16] public adopters;
mapping(uint => string) idByName;
mapping(uint => address) idByAddress;
constructor() public {
idByName[1] = "111";
idByName[2] = "222";
idByName[3] = "333";
idByName[4] = "444";
idByName[5] = "555";
}
function adopt(uint petId) public returns (uint) {
require(petId >= 0 && petId <= 15);
adopters[petId] = msg.sender;
return petId;
}
function getAdopters() public view returns (address[16]) {
return adopters;
}
function say() public pure returns(string){
return "Hello world";
}
function print(string name) public pure returns (string) {
return name;
}
function getNameById(uint _value) public view returns(string) {
return idByName[_value];
}
function insertName(uint _value,string _name) public {
idByName[_value] = _name;
}
function insertAddress(uint _value,address _addr) public{
idByAddress[_value] = _addr;
}
function getAddressById(uint _value) public view returns(address) {
return idByAddress[_value];
}
}
拷贝到本地并命名为adoption.sol
在cmd里使用`npm install solc`,我安装的时候的版本号`[email protected]`
新建一个js文件,并命名为`compiler.js`,代码如下
var solc = require("solc")
var fs = require("fs")
var path = require('path')
function compiler(file,contractName){
// 读取智能合约文件
input = fs.readFileSync(file,'utf8').toString();
var fileName = path.parse(file)['name'].toString();
console.log(fileName)
// 编译合约
var contract = solc.compile(input,1);
// 输出结果
console.log(contract.contracts[contractName].bytecode)
console.log(contract.contracts[contractName].interface)
// 将编译后生成的bytecode保存到本地
fs.writeFile(fileName+'.abi','0x'+contract.contracts[contractName].bytecode,{},function (err,result) {
if (err){
console.log(err)
}
})
// 将编译后生成的interface保存到本地
fs.writeFile(fileName+'.json',(contract.contracts[contractName].interface),{},function (err,result) {
if (err){
console.log(err)
}
})
}
// 调用函数,第一个参数是你的合约文件地址,第二个参数是你的合约名,注意冒号不要省略
compiler('adoption.sol',':Adoption');
在cmd里使用`npm install web3`等待插件安装完成。我的安装版本`[email protected]`
新建js文件并命名为`deploy.js`
注意:部署合约之前需要在本地开启私链,怎么部署私链可以百度解决,如果实在不会可以在下面给我留言,我们的私链地址`http://127.0.0.1:8545`。开启私链记得把rpc,rpcapi等选项打开,下面给出我的参数:
`geth --datadir=private_chain --rpc --rpcapi='db,eth,net,web3,personal,web3' console`
var Web3 = require('web3');
var web3 = new Web3(new Web3.providers.HttpProvider('http://127.0.0.1:8545'));
var fs = require('fs')
var path = require('path')
deploy('adoption','0x3c6ae9c096701ddfee4f6acc2d63e6a7449b48de','123456');
/*
@param file 文件名,会自动查找文件名路径下的被编译过的文件
@param from 合约账户,合约部署到私链上将从这个账户上扣除gas
@param password 该账户的密码,如果你账户是锁定状态
*/
function deploy(file,from,password) {
var filename = path.parse(file)['name'].toString();
var interface = fs.readFileSync(file+'.json').toString();
var bytecode = fs.readFileSync(file+'.abi').toString();
var MyContract =new web3.eth.Contract(JSON.parse(interface),{from:from,gasPrice:'1597262155',gas:3000000,data:bytecode});
// 如果你的账户是未锁定状态,可以将这里去掉
web3.eth.personal.unlockAccount(from,password,function (err,result) {
if (err){
console.log(err)
}
if (result){
// 只保留这些
MyContract.deploy({
data:bytecode,
})
.send({
from: from,
gas: 3000000,
gasPrice: '1597262155',
value:0
},function (error,transactionHash) {
if (error)
console.log(error)
console.log(transactionHash)
})
.on('error', function (error) {
console.log(error)
})
.on('transactionHash',function (transactionHash) {
console.log(transactionHash)
})
.on('receipt',function (receipt) {
console.log(receipt)
})
.on("confirmation", function (confirmationNumber,receipt) {
console.log(confirmationNumber)
console.log(receipt)
})
.then(function(newContractInstance){
console.log(newContractInstance.options.address) // instance with the new contract address
// 将合约部署的地址保存到本地
fs.writeFile(filename+'address.txt',newContractInstance.options.address,{},function (err,result) {
if (err){
console.log(err)
}
console.log('contract address write into contractAddress.txt');
})
});
}
})
}
运行之后你会在私链的cmd中看到如下打印输出。每个人的打印输出都不一样,但是`Submitted contract creation`这个是一定有的。`contract=0x2c722d220113F9e6C2eA0E364B5169C28D2732DC`这个就是刚部署的合约地址,`fullhash`是交易hash值
```
> INFO [09-06|18:24:40.108] Submitted contract creation fullhash=0x7a73615637012987613a0570db8e0651cbe0d07eb8ca1de6ae6103b1d146609b contract=0x2c722d220113F9e6C2eA0E364B5169C28D2732DC
```
我们在私链的cmd里面开启挖矿,处理这笔交易,输入`miner.start()`,等处理完成之后再输入`miner.stop()`。程序执行完成之后你会在下面看到一堆输出日志。看不懂就不用管。这些暂时不是今天讨论的重点。
合约现在部署到私链上了,现在我们要跟合约交互。
新建一个js文件,命名为`callContract.js`
var Web3 = require('web3');
var web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'));
var fs = require('fs')
var abi = fs.readFileSync('adoption.json').toString();
// 获取合约实例,把刚才部署好的合约地址放在这里
var MyContract =new web3.eth.Contract(JSON.parse(abi),'0x2c722d220113F9e6C2eA0E364B5169C28D2732DC');
```
合约调用分为两种,一种是读取合约里面的数据,不需要消耗gas,另一种是向合约写入数据,是需要消耗gas的
下面演示call方法
```JavaScript
function say(from) {
// say函数是没有参数的方法
MyContract.methods.say().call({from:from},function(err,result){
if (err) {
console.log(err)
}
console.log(result)
})
}
function getNameById(from,id){
MyContract.methods.getNameById(id).call({from:from},function(err,result){
if (err) {
console.log(err)
}
console.log(result)
})
}
// 调用函数,输入调用账户地址
say("0x3c6ae9c096701ddfee4f6acc2d63e6a7449b48de")
getNameById("0x3c6ae9c096701ddfee4f6acc2d63e6a7449b48de",1)
打印输出:
```
111
Hello world
```
下面演示send方法
/* send方法
// send方法会修改合约数据,所以需要账户为解锁状态,或者可以在开启私链的时候设置,我们下面编写一个解锁账户的函数
// 解锁账户,result为返回结果,解锁成功为true
@param from 账户地址
@param password 账户密码
@param youFunction 回调函数
*/
function unlockAccount(from,password,youFunction){
web3.eth.personal.unlockAccount(from,password,function (err,result) {
if (err){
console.log(err)
}
if (result){
console.log(result)
youFunction();
}
})
}
// insertName,请对照合约里面的同名函数查看
function insertName(from,id,name) {
MyContract.methods.insertName(id,name).send({from:from},function(err,result){
if (err) {
console.log(err)
}
console.log(result)
})
}
调用演示,使用匿名函数,需要等到账户被解锁之后才能调用,调用之后需要去开启挖矿
unlockAccount("0x3c6ae9c096701ddfee4f6acc2d63e6a7449b48de","123456",function(){
insertName("0x3c6ae9c096701ddfee4f6acc2d63e6a7449b48de",6,"666")
})
打印输出为一段hash值
检验我们的数据是否有写入成功
getNameById("0x3c6ae9c096701ddfee4f6acc2d63e6a7449b48de",6)
打印输出
```
666
```
教程到这里基本结束,有什么不明白的地方可以给我留言
callContract.js完整代码如下
var Web3 = require('web3');
var web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'));
var fs = require('fs')
var abi = fs.readFileSync('adoption.json').toString();
// 获取合约实例,把刚才部署好的合约地址放在这里
var MyContract =new web3.eth.Contract(JSON.parse(abi),'0x2c722d220113F9e6C2eA0E364B5169C28D2732DC');
// call方法
function say(from) {
// say函数是没有参数的方法
MyContract.methods.say().call({from:from},function(err,result){
if (err) {
console.log(err)
}
console.log(result)
})
}
function getNameById(from,id){
MyContract.methods.getNameById(id).call({from:from},function(err,result){
if (err) {
console.log(err)
}
console.log(result)
})
}
// 调用函数,输入调用账户地址
say("0x3c6ae9c096701ddfee4f6acc2d63e6a7449b48de")
getNameById("0x3c6ae9c096701ddfee4f6acc2d63e6a7449b48de",1)
/* send方法
// send方法会修改合约数据,所以需要账户为解锁状态,或者可以在开启私链的时候设置,我们下面编写一个解锁账户的函数
// 解锁账户,result为返回结果,解锁成功为true
@param from 账户地址
@param password 账户密码
@param youFunction 回调函数
*/
function unlockAccount(from,password,youFunction){
web3.eth.personal.unlockAccount(from,password,function (err,result) {
if (err){
console.log(err)
}
if (result){
console.log(result)
youFunction();
}
})
}
// insertName,请对照合约里面的同名函数查看
function insertName(from,id,name) {
MyContract.methods.insertName(id,name).send({from:from},function(err,result){
if (err) {
console.log(err)
}
console.log(result)
})
}
调用演示,使用匿名函数,需要等到账户被解锁之后才能调用,调用之后需要去开启挖矿
unlockAccount("0x3c6ae9c096701ddfee4f6acc2d63e6a7449b48de","123456",function(){
insertName("0x3c6ae9c096701ddfee4f6acc2d63e6a7449b48de",6,"666")
})
// 下面我们验证下是否调用成功
getNameById("0x3c6ae9c096701ddfee4f6acc2d63e6a7449b48de",6)