在智能合约编写完成后,部署的方式就提到了日程上来,经过简单的测试,总结出来以下几种编译部署方式:
一、编译
solc安装方式非常简单,可以直接命令安装也可以使用源码编译。使用方法:
solcjs --bin name.sol 获得bytecode
solcjs --abi name.sol 获得abi
或者二合一:
solcjs --bin --abi name.sol
需要注意的是,如果不增加编译参数,那么因为优化程度不同可能同Remix上编译得到的略有不同。
将代码直接拷贝到如下网址:
http://remix.ethereum.org
在其中编译即可,如果不编译,可能需要在setting中选择一下编译器的版本。编译成功后,点击Details,即可得到相关的参数值。
这个在上篇的一键部署中有详细介绍,这里不再赘述。主要是安装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地址来决定连接的网络。如果都连接本地网,那么它和第二项没啥区别。
重点讲一下这个,这个弄明白了,下面的也就是增加一个签名而已:
首先部署一个最简单的合约,说明使用流程;其次部署一个发币合约,来说明整个流程,具体步骤见后面代码。
这个就比较简单了,使用上篇博文的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
> 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++和区块链感兴趣,欢迎关注: