最近学习以太坊,以太坊最重要的就是部署合约,部署合约的方式有很多种,最常用的就是truffle框架,部署也比较方便,简单,但是我用truffle的 truffle test却一直超时…不懂为啥,这里记录下使用在线编译智能合约的步骤。
以太坊solidity在线编译地址
geth的搭建环境和构建私有连比较简单,csdn博客很多,自行看下就好了啦
第一个启动以太坊的console控制台,启动参数可参考如下
mygeth.exe --identity "newEth" --rpc --rpccorsdomain "*" --datadir "%cd%\chain" --port 30303 --rpcapi "db,eth,net,web3" --networkid 9999 console
大概是这样的
第二个 新开一个终端连接以太坊的console,参考命令
geth attach http://127.0.0.1:8545
,通过geth attach来连接,后面就是ip和端口,默认端口是8545,可通过第一个启动进行自定义。
连接上之后大概是这样的
必须有一个账户,并且账户里面要有etc
web3.js的API
创建账户命令
personal.newAccount('aaa111')
单引号里面的是密码
查看账户命令
personal.listAccounts
查看默认挖矿的账号命令
web3.eth.coinbase
启动挖矿的命令
miner.start(1)
总的来说 就是部署合约的前提条件是你必须要有一个账户,并且账户里面要有钱(多点好),然后再部署合约的时候需要解锁账户,只有解锁了账户才能把合约部署上去
下面这段代码是个很简单的智能合约代码
pragma solidity ^0.4.4;
contract test {
function multiply(uint a) returns(uint d){
return a * 6;
}
}
把上述代码拷贝到solidity在线编译器上面进行编译,如下图
把代码拷贝到中间,然后点击Start to compile按钮,右边会出现警告,忽略没有关系,我们测试的很简单,编译完成之后,点开旁边的Details。大概的图是这样的,这里只截取了一小部分,具体的点开看一下里面的注释就知道了…
我们找到Detail中的WEB3DEPLOY段落,这个就说怎么用web3进行部署,下面有两个命令,我们一次执行下
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: '0x6060604052341561000f57600080fd5b60b18061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa1146044575b600080fd5b3415604e57600080fd5b606260048080359060200190919050506078565b6040518082815260200191505060405180910390f35b60006006820290509190505600a165627a7a72305820bfce4073e896a63a9888320f0d5d07c04954fdb3c0420f79e3170786b086c9ff0029',
gas: '4700000'
}, function (e, contract){
console.log(e, contract);
if (typeof contract.address !== 'undefined') {
console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
}
})
执行效果
> 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.new(
... {
...... from: web3.eth.accounts[0],
...... data: '0x6060604052341561000f57600080fd5b60b18061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa1146044575b600080fd5b3415604e57600080fd5b606260048080359060200190919050506078565b6040518082815260200191505060405180910390f35b60006006820290509190505600a165627a7a72305820bfce4073e896a63a9888320f0d5d07c04954fdb3c0420f79e3170786b086c9ff0029',
...... gas: '4700000'
...... }, function (e, contract){
...... console.log(e, contract);
...... if (typeof contract.address !== 'undefined') {
......... console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
......... }
...... })
Error: authentication needed: password or unlock undefined
undefined
>
我们看到执行第二条命令的时候报错了,Error: authentication needed: password or unlock undefinedu
,这是因为账户没有解锁,那我们就解锁下
> personal.unlockAccount(eth.accounts[0],"aaa111",1000000)
true
>
返回true解锁成功,然后再执行上面命令中的第二条命令,这个时候就没有报错了,
执行命令之后会出现这样的一段文字(出现这段文字的前提是你的第一个终端是在挖矿状态),address就是合约地址
Contract mined! address: 0xd26db0df7644ed6b1e46839273591bcd67cbcefd
transactionHash: 0xde6570c862fff92f282fddf84901a0e376a3f972e7be8831eccbe2b2220a8e4a
在第二个终端执行,引号里面的值就是合约的地址,这里定义了一个tt变量,然后通过tt调用方法multiply(),后面的call(3)大概就是调用的意思。
> tt=eth.contract(test.abi).at("0xd26db0df7644ed6b1e46839273591bcd67cbcefd")
> tt.multiply.call(3)
18
这个合约我们写的是一个数字乘以6,3*6结果是18,测试就调用成功了。
查看合约的字节码和abi
bytecode在detail的BYTECODE框框里面,点击旁边的copy按钮可复制出来,json中的object就是字节码。
{
"linkReferences": {},
"object": "6060604052341561000f57600080fd5b60b18061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa1146044575b600080fd5b3415604e57600080fd5b606260048080359060200190919050506078565b6040518082815260200191505060405180910390f35b60006006820290509190505600a165627a7a72305820bfce4073e896a63a9888320f0d5d07c04954fdb3c0420f79e3170786b086c9ff0029",
"opcodes": "PUSH1 0x60 PUSH1 0x40 MSTORE CALLVALUE ISZERO PUSH2 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0xB1 DUP1 PUSH2 0x1D PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x60 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH1 0x3F JUMPI PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV PUSH4 0xFFFFFFFF AND DUP1 PUSH4 0xC6888FA1 EQ PUSH1 0x44 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE ISZERO PUSH1 0x4E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x62 PUSH1 0x4 DUP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP2 SWAP1 POP POP PUSH1 0x78 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH1 0x0 PUSH1 0x6 DUP3 MUL SWAP1 POP SWAP2 SWAP1 POP JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 0xbf 0xce BLOCKHASH PUSH20 0xE896A63A9888320F0D5D07C04954FDB3C0420F79 0xe3 OR SMOD DUP7 0xb0 DUP7 0xc9 SELFDESTRUCT STOP 0x29 ",
"sourceMap": "27:103:0:-;;;;;;;;;;;;;;;;;"
}
abi在detail的ABI框框里面,点击旁边的copy按钮可复制出来,在remix的在线编译器中,看不到具体的abi的值,只能复制出来才能看到。案例的abi值大概是这样的
[{
"constant": false,
"inputs": [{
"name": "a",
"type": "uint256"
}],
"name": "multiply",
"outputs": [{
"name": "d",
"type": "uint256"
}],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}]
预估手续费
bytecode="0x6060604052341561000f57600080fd5b60b18061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa1146044575b600080fd5b3415604e57600080fd5b606260048080359060200190919050506078565b6040518082815260200191505060405180910390f35b60006006820290509190505600a165627a7a72305820bfce4073e896a63a9888320f0d5d07c04954fdb3c0420f79e3170786b086c9ff0029"
查看手续费命令
web3.eth.estimateGas({data: bytecode})//bytecode就是上面定义的(注意前面需要加0x)
call的原因是因为multiply函数没有添加constant。
参考博客:
http://www.8btc.com/ethereum-private-chain
http://blog.csdn.net/u013096666/article/details/72765491