使用nodejs编译智能合约,部署合约,调用合约

使用nodejs编译智能合约

nodejs环境搭建,自行百度解决
新建工程

  • 新建项目工程文件夹,进入文件夹

  • 在`cmd`里使用`npm install solc`

  • 智能合约,以下提供一个简单的智能合约

  • 使用nodejs编译智能合约

  • 将智能合约部署到私链上

  • 使用nodejs,web3访问智能合约

具体步骤一共分为以上几步。
手把手一步一步操作教程:
1. 智能合约,下面是个简单的合约


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

2. 安装`solc`插件

   在cmd里使用`npm install solc`,我安装的时候的版本号`[email protected]`

3. 编译合约


新建一个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');


4. 安装`web3`插件。


在cmd里使用`npm install web3`等待插件安装完成。我的安装版本`[email protected]`

5. 部署合约


新建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()`。程序执行完成之后你会在下面看到一堆输出日志。看不懂就不用管。这些暂时不是今天讨论的重点。


6. 调用合约


合约现在部署到私链上了,现在我们要跟合约交互。
新建一个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)

 

你可能感兴趣的:(智能合约,合约编译,合约部署,合约调用)