合约的自动编译和一键部署

在开发智能合约时,有时候儿需要对合约自动化部署,通过一条指令或者调用一个文件来完成,下面给出一个思路,供借鉴:

  • 环境的安装

1、安装 相关软件

 [root@k7762v /home]# yum install git

[root@k7762v /home]# yum install openssl-devel

 

[root@k7762v /home]# npm install -g ethereumjs-testrpc

[root@k7762v /home]# npm install -g truffle

 

[root@k7762v /home]# yum install -y curl  golang

如果在安装web3时,警告找不到package.json,下面是解决这个警告或者错误的一种方法:

npm init -f

然后再次运行

# npm install web3

2、创建工作目录并配置环境变量

mkdir ~/go

echo "export GOPATH=$HOME/go" >> /etc/profile

source /etc/profile

3、创建Truffles

1)、空项目:truffle init

2)、复杂WEB

[root@k7762v /home/testmy]# truffle unbox webpack

4、如果tesrpc出现错误端口情况:

说明:testrpc已被废弃,现已更名为Ganache CLI

lsof -i:8545 找到pid 然后 kill -9 pid

但是本次安装这个进程是DOCKER进程 ID,暂时还不能杀。

5、安装CMAKE3.9,编译SOLC

wget https://cmake.org/files/v3.9/cmake-3.9.2.tar.gz 

tar xvf cmake-3.9.2.tar.gz && cd cmake-3.9.2

./configure && make && make install

6、安装SOLC

编译安装:

git clone --recursive https://github.com/ethereum/solidity.git  

cd solidity

mkdir build

cd build

cmake .. && make  

但是这里编译需要boost库,要提前安装。不过有简单的方法:

命令安装:

sudo npm install -g solc solc-cli --save-dev

如果在使用时仍然报缺少哪个,就再安装一次就好了。

7、安装solcjs

如果安装了第六步的命令安装,本步可省略。

npm install -g solc

npm install solc   //遇到找不到SOLC模块,再来一次

8、数据库客户端安装访问

安装方法:

npm install mysql

如果有错误缺少json文件,可按照上面web3安装时的方法init或者手动创建:

package.json

 

{

    "name":    "mysqltest",

    "description": "test project",

    "version": "0.0.1",

    "private": true,

    "devDependencies":{

        "mysql":"2.6.2"

   }

}

访问:

mysql -h110.212.41.17 -P3306 -p –u用户名  数据库名

提示输入密码,输入密码即可。

根据需要来创建一个表,例如:

CREATE TABLE `contract` (

         `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,

         `name` VARCHAR(50) NULL DEFAULT NULL,

         `abi` TEXT NOT NULL,

         `addr` VARCHAR(200) NOT NULL DEFAULT '0x',

         PRIMARY KEY (`id`)

)

COLLATE='utf8_general_ci'

ENGINE=InnoDB

;

 

  • 合约的编译

此处采用多文件遍历:

const fs = require('fs');

const path = require('path');

const solc = require('solc');

 

//const CONTRACTS_DIR = path.resolve(__dirname, 'contracts');

const CONTRACTS_DIR = path.resolve(__dirname);

 

function findContract(pathName) {

    const contractPath = path.resolve(CONTRACTS_DIR, pathName);

    if (isContract(contractPath)) {

        return fs.readFileSync(contractPath, 'utf8');

    } else {

        throw new Error(`File ${contractPath} not found`);

    }

}

 

function isContract(path) {

    return fs.existsSync(path);

}

 

function findImports (pathName) {

    try {

        return { contents: findContract(pathName) };

    } catch(e) {

        return { error: e.message };

    }

}

 

const source = findContract('xxx.sol');//主要的 sol

const compiled = solc.compile({

    sources: {

        'xxx' : source

    }

}, 1, findImports);//1表示编译最优,findImports会自动传入依赖的sol,可以在此函数内打印路径显示依赖

 

for (var cn in compiled.contracts){

        console.log(JSON.parse(compiled.contracts[cn].interface));

        console.log(compiled.contracts[cn].bytecode);

}

~

 

  • 合约的自动部署和保存

 

var Web3 = require('web3');

var fs = require('fs');

const solc = require('solc');

var web3;

 

var id = 0;//默认值

var clientid ='';

var serviceid = '';

var dbip ='110.212.41.17';

var dbport=3306;

var usename ='test';

var pwd ='123456';

var dbname = 'my_baas';

 

var count = getConfig();

if (count < 3){

        return;

}

 

console.log('create web3 instance');

 

if (typeof web3 !== 'undefined'){

    web3 = new Web3(web3.currentProvider);

    console.log("new currenprovider");

}

else

{

   console.log("http remote rpc create");

    web3 = new Web3(new Web3.providers.HttpProvider("http://127.0.0.1:8089"));

    console.log("isok http");

}

 

//初始化数据库模块

var maxid = 0;

console.log("init mysql ....");

var mysql  = require('mysql');

var connection = mysql.createConnection({

        host:dbip,

        user:'root',

        password:'123456',

        port:dbport,

        database:'test'

});

 

//var id0 = selectID();

console.log('Reading Contract xxxx...');

 

var input = {

        'xxx0.sol':fs.readFileSync("./xxx0.sol","utf-8"),

        'xxx.sol':fs.readFileSync("./xxx.sol","utf-8")

};

 

console.log('start compile.....');

const output = solc.compile({sources:input},1);

let abi = JSON.parse(output.contracts['xxx.sol:xxx'].interface);

let bytecode = output.contracts['xxx.sol:xxx'].bytecode;

//save db

console.log("save abi and bytecode ......");

insertTable(id,'',abi,bytecode);

 

//获得Gas

function getGas(){

        let gasEstimate = web3.eth.estimateGas({data: '0x' + bytecode});

        console.log(gasEstimate);

}

//处理参数

function getConfig(){

        //处理输入参数

        var args = process.argv.splice(2);

        console.log(args);

 

        //获得参数个数

        var num = args.length;

        if (num < 3){

                console.log("params count is too small!");

                return num;

        }

 

        id = args[0];

        clientid = args[1];

        serviceid = args[2];

 

        if ("" == args[3] || null == args[3]  ){

                console.log('err value is: ' + args[3]);

                return num;

        }

        dbip = args[3];

        console.log('dbip value is: '+dbip);

        dbport = args[4];

 

        console.log(id,clientid,serviceid);

}

 

//部署--应该使用原始签名,此处不再使用

function deployContract(){

        var adTokenContract=new web3.eth.Contract(abi).deploy({

                data:'0x'+bytecode,     //以0x开头

                arguments:[10000000000,"TAG",2],       //传递构造函数的参数

        }).send({

                //from:account,

                from:"0xcb4f30359dae96e70c30e3e1cdf76e3ef8b3bb4f",

                //gas:4700000,

                gas:4700000,

                //gasPrice:'30000000000000'

        },function(error,transactionHash){

                console.log("send回调");

                console.log("error:"+error);

                console.log("send transactionHash:"+transactionHash);

        })

        .on('error', function(error){ console.error(error) })

        .then(function(newContractInstance){

                var newContractAddress=newContractInstance.options.address

                console.log("新合约地址:"+newContractAddress);

                insertTable(id,'',abi,newContractAddress);

        });

}

//选择数据库

function selectID(){

        connection.connect();

        var sel = "select max(id) as id  from contract";

        connection.query(sel,function(error, results, fields){

                if (error) {

                        console.log("error:",error.message);

                        throw error;

                }

                 if (results) {

                 console.log("maxid is:",results[0].id + 1);

                 id = parseInt( results[0].id) + 1;

 

                 }

        });

        //connection.end();

}

 

//插入数据库ABI及地址

function insertTable(id,name,abi,addr){

        connection.connect(function(err){

         if(err){

                console.log('[query] - :'+err);

                 return;

 

        }

        console.log('[connection connect]  succeed!');

 

        });

 

        var abistr = JSON.stringify(abi);

        id = 33;

 

        var insertSql =

"insert into contract(id,name,abi,addr)values("+id+",'"+name+"','"+abistr+"','"+addr+"')";

        console.log(insertSql);

 

        connection.query(insertSql,function(err,result){

                 if (err){

                        console.log('[insert error]-',err.message);

                        return;

                }

 

                 console.log('insert id:',result);

 

        });

 

}

//关闭数据库连接

function Close(){

        connection.end(function(err){

                if(err){

                return;

        }

        console.log('[connection end] succeed!');

});

 

}

  • 签名交易自动管理方式处理发送合约

需要安装ethereumjs-tx

var Tx = require('ethereumjs-tx');

var privateKey = new Buffer('e331b6d69882b4cb4ea581d88e0b604039a3de5967688d3dcffdd2270c0fd109', 'hex')

 

var rawTx = {

  nonce: '0x00',

  gasPrice: '0x09184e72a000',

  gasLimit: '0x2710',

  to: '0x0000000000000000000000000000000000000000',

  value: '0x00',

  data: '0x7f7465737432000000000000000000000000000000000000000000000000000000600057'

}

 

var tx = new Tx(rawTx);

tx.sign(privateKey);

 

var serializedTx = tx.serialize();//序列化???

 

//console.log(serializedTx.toString('hex'));

//f889808609184e72a00082271094000000000000000000000000000000000000000080a47f74657374320000000000000000000000000000000000000000000000000000006000571ca08a8bbf888cfa37bbf0bb965423625641fc956967b81d12e23709cead01446075a01ce999b56a8a88504be365442ea61239198e23d1fce7d00fcfc5cd3b44b7215f

 

web3.eth.sendRawTransaction('0x' + serializedTx.toString('hex'), function(err, hash) {

  if (!err)

    console.log(hash); // "0x7f9fade1c0d57a7af66ab4ead79fade1c0d57a7af66ab4ead7c2c2eb7b11a91385"

});

只需要把编译智能合约的bytecode部分放到data中,签名发送即可。交易完成后调用:

web3.eth.getTransactionReceipt(交易哈希)获取合约的地址。

  • 总结

通过上述的一系列工作,就可以编译部署一个智能合约了,如果你想自动化部署可以考虑这么做,更方便。

如果你对c++和区块链感兴趣,欢迎关注:

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐