智能合约的编译部署方式

 

在智能合约编写完成后,部署的方式就提到了日程上来,经过简单的测试,总结出来以下几种编译部署方式:

一、编译

  1. solc编译

solc安装方式非常简单,可以直接命令安装也可以使用源码编译。使用方法:

solcjs --bin name.sol  获得bytecode

solcjs --abi name.sol  获得abi

或者二合一:

solcjs --bin  --abi name.sol

需要注意的是,如果不增加编译参数,那么因为优化程度不同可能同Remix上编译得到的略有不同。

  1. remix编译

将代码直接拷贝到如下网址:

http://remix.ethereum.org

在其中编译即可,如果不编译,可能需要在setting中选择一下编译器的版本。编译成功后,点击Details,即可得到相关的参数值。

  1. node.js编译

这个在上篇的一键部署中有详细介绍,这里不再赘述。主要是安装node.js,solc,web3.js等相关内容。

这里有一个需要注意的地方,在老的版本中提供了eth.compile.solidity这个属性,但是在新的版本中,已经去除,编译时会报找不到solidity这个属性。

二、部署

1、geth部署

方法非常简单,把abi,bytecode组成类似Remix上的格式拷贝到命令行中执行即可:

var testContract =

web3.eth.contract([{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]);

var test = testContract.new(

   {

     from: web3.eth.accounts[0],

     data: '0x6080604052348015600f57600080fd5b50609c8061001e6000396000f300608060405260043610603e5763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663c6888fa181146043575b600080fd5b348015604e57600080fd5b506058600435606a565b60408051918252519081900360200190f35b600701905600a165627a7a72305820325aa8f93a172a9ced694be2e82a701fb1871a9a30185f1259d5aadc28b44fcc0029',

     gas: '4700000'

   }, function (e, contract){

    console.log(e, contract);

    if (typeof contract.address !== 'undefined') {

         console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);

    }

 })

这里需要注意的是,如果有参数需要将参数数据设置好,并在new的时候儿将其填充到前面,细节看上篇的内容。

2、remix部署

这个就更简单了,编译成功后,点击Run,在”Environment”中选择部署的方式,有三种方式:

javascriptVM:这个类似于使用JS的虚拟机来测试部署。

injected Web3:使用MetaMask这个插件的选项,发币相当简单,其实就是一个大号的钱包。功能强大,简单易用。它内部可以选择是使用测试网还是主网,一用就明白了。没有什么可讲的。

Web3 Provider:使用URL地址来决定连接的网络。如果都连接本地网,那么它和第二项没啥区别。

  1. node.js部署
  1. 使用本地的Web3来部署,如上一篇博客所讲。
  2. 使用eth_sendTransaction

重点讲一下这个,这个弄明白了,下面的也就是增加一个签名而已:

首先部署一个最简单的合约,说明使用流程;其次部署一个发币合约,来说明整个流程,具体步骤见后面代码。

  1. 使用eth_sendRawTransaction

这个就比较简单了,使用上篇博文的ethereumjs-tx来签名发送即可。需要注意的,这里需要自己处理 nonce, 方法很多,可以用web3.eth.getTransactionCount(web3.eth.coinbase),也可以使用自己写代码控制的方式。

4、其它方式

可以使用一些现成的插件或者软件,比如metamask, etherscan等,还有好多的钱包都自带这个功能。不一一介绍。

三、具体步骤

A、部署简单合约:

1、内容源码

pragma solidity ^0.4.2;

contract test {

 

   function multiply(uint a) returns(uint d) {

       return a + 7;

   }

}

2、Remix编译(如果真正编码可以使用上篇博客方法)

var testContract =

web3.eth.contract([{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]);

var test = testContract.new(

   {

     from: web3.eth.accounts[0],

     data: '0x6080604052348015600f57600080fd5b50609c8061001e6000396000f300608060405260043610603e5763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663c6888fa181146043575b600080fd5b348015604e57600080fd5b506058600435606a565b60408051918252519081900360200190f35b600701905600a165627a7a72305820325aa8f93a172a9ced694be2e82a701fb1871a9a30185f1259d5aadc28b44fcc0029',

     gas: '4700000'

   }, function (e, contract){

    console.log(e, contract);

    if (typeof contract.address !== 'undefined') {

         console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);

    }

 })

 

3、部署

//拆出Code,记得要有0x

var mul =

'0x6080604052348015600f57600080fd5b50609c8061001e6000396000f300608060405260043610603e5763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663c6888fa181146043575b600080fd5b348015604e57600080fd5b506058600435606a565b60408051918252519081900360200190f35b600701905600a165627a7a72305820325aa8f93a172a9ced694be2e82a701fb1871a9a30185f1259d5aadc28b44fcc0029'

//交易部署--gas好多都不写,但是最好按Remix上生成的写,这样成功概率较大

> eth.sendTransaction({from:eth.accounts[0],gas:"4700000",data:code})

"0x4ac72df85e34a046acbdc84f00ec5a5d9601743a64542f3908cb49bebeb3efc3"   //交易地址

> eth.getTransactionReceipt("0x4ac72df85e34a046acbdc84f00ec5a5d9601743a64542f3908cb49bebeb3efc3")

{

  blockHash: "0xa05929f6bfee471cf8cd26f65ca5119b94571d40fa44bc08167a1fce663f557c",

  blockNumber: 1272122,

  contractAddress: "0x88592cee126acdfaab33cc26011c0652c826537b",//合约地址

  cumulativeGasUsed: 94497,

  from: "0xcb4f30359dae96e70c30e3e1cdf76e3ef8b3bb4f",

  gasUsed: 94497,

  logs: [],

  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",

  status: "0x1",

  to: null,

  transactionHash: "0x4ac72df85e34a046acbdc84f00ec5a5d9601743a64542f3908cb49bebeb3efc3",

  transactionIndex: 0

}

4、验证

 

> var testContract =

web3.eth.contract([{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]);

undefined

> var test = testContract("0x88592cee126acdfaab33cc26011c0652c826537b")

TypeError: 'testContract' is not a function

    at :1:12

 

> var test = testContract.at("0x88592cee126acdfaab33cc26011c0652c826537b")

undefined

> test.multiply.c

test.multiply.call test.multiply.caller test.multiply.constructor

> test.multiply.call(111)

118

>

B、部署发币合约

1、获得参数代码:

//获得三个构造函数参数的二进制值

var init_amount = web3.eth.abi.encodeParameter('uint256','100000000');

console.log(init_amount);

 var token_name = web3.eth.abi.encodeParameter('string','PPAA');

console.log(token_name);

   var decimals = web3.eth.abi.encodeParameter('uint8','2');

console.log(decimals.substr(2,decimals.length));

 

0x0000000000000000000000000000000000000000000000000000000005f5e1000x0000000000000000000000000000000000000000000000000000000000000002

0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000000000002

 

//测试数组参数

var input=['uint256','string','uint8'];

var parray=['100000000','PPAA','2'];

var arrayParams=web3.eth.abi.encodeParameters(input,parray);

console.log(arrayParams);

 

 

打印的值如下:

var p1='0x0000000000000000000000000000000000000000000000000000000005f5e100'

var p2='0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000045050414100000000000000000000000000000000000000000000000000000000'

var p3='0x0000000000000000000000000000000000000000000000000000000000000002'

 

//真正使用不能有0x

var p1='0000000000000000000000000000000000000000000000000000000005f5e100'

var p2='000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000045050414100000000000000000000000000000000000000000000000000000000'

var p3='0000000000000000000000000000000000000000000000000000000000000002'

2、获得bytecode

方法可使用代码也可以在Remix上获得(主要是为了测试方便)

var bytecode=

'0x60c0604052600b60808190527f76657273696f6e20302e3100000000000000000000000000000000000000000060a…………….660009081526006602065627a7a72305820f92b013f7ea3316c8959558faabe5689c3306deef20d6b41dd05d84a3d28b3d10029'

当中省略了好多编码。

3、组装交易数据

var code = bytecode + p1+p2+p3

4、发送合约交易

> eth.sendTransaction({from:eth.accounts[0],gas:"4700000",data:code})

"0x41426aa4ca6d8de14054fe3f2b9cd2a7ad4acb95f1ae49d3ec92a1b645988739"

获取合约地址

> eth.getTransactionReceipt("0x41426aa4ca6d8de14054fe3f2b9cd2a7ad4acb95f1ae49d3ec92a1b645988739")

{

  blockHash: "0x6ef44c265262a4527432614c1c61bade9c8ad83d891a4d5e992423429a004a04",

  blockNumber: 1273042,

  contractAddress: "0xfbf4cd4de60fecc9a56ffae2804a33470ba10522",

  cumulativeGasUsed: 1470159,

  from: "0xcb4f30359dae96e70c30e3e1cdf76e3ef8b3bb4f",

  gasUsed: 1470159,

  logs: [],

  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",

  status: "0x1",

  to: null,

  transactionHash: "0x41426aa4ca6d8de14054fe3f2b9cd2a7ad4acb95f1ae49d3ec92a1b645988739",

  transactionIndex: 0

}

5、验证测试

注意,bytecode当中省略了部分代码,详细参看前面的自动化部署

> var ad =

web3.eth.contract([{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],…………"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"}]);

undefined

> var token = ad.at("0xfbf4cd4de60fecc9a56ffae2804a33470ba10522")

undefined

> token.balanceOf(eth.accounts[0])

100000000

>

C、遇到的问题

1、在发送交易时没有写gas,虽然发送成功并且得到合约地址,但执行函数总是出错,目前无法正式确定是偶然因素还是必然因素。所以最好写上Remix上建议的值 。

2、参数顺序保持一致,并且没有0x

3、那个web3.eth.abi.encodeParameters是编码数组的,分析得到的结果和在官网上ABI的编码数组格式一致。

四、原始交易的签名方法

1、使用web3.eth.sign

需要解锁用户的权限,用web3编程。

2、使用ethereumjs-tx

直接附上私钥。

3、自己实现签名交易

这个可以看一下相关的源码,比如上面的ethereumjs-tx或者以太坊的源码等来实现一套源码。

五、总结

通过上述的分析再配合上一篇的自动化部署,这样就可以实现从多个角度来实现自动化部署一个合约。

正如大家担心的,如果使用普通的交易方式,签名的私钥一直暴露在网络上,而如果使用交易签名后,再使用eth_sendRawTransaction来发送合约就安全了。

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

智能合约的编译部署方式_第1张图片

你可能感兴趣的:(blockchain,blockchain)