首先我们进去geth平台
root@i-colbyo7v:/home/ubuntu# cd private-geth/
root@i-colbyo7v:/home/ubuntu/private-geth# geth --identity "haha" --datadir ./data/00 --networkid 12345 --rpcapi "db,eth,net,web3" --port 61910 --rpcport 8200 console
Welcome to the Geth JavaScript console!
instance: Geth/haha/v1.6.6-stable-10a45cb5/linux-amd64/go1.8.1
coinbase: 0x8260b02ac49855f9c00ff4275dc5291300517e30
at block: 48 (Tue, 11 Jul 2017 15:21:41 CST)
datadir: /home/ubuntu/private-geth/data/00
modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0
合约部署流程
一般来说,部署智能合约的步骤为
1启动一个以太坊节点 (例如geth或者testrpc)。
2用solc编译智能合约。 => 获得二进制代码。
3编译好的合约部署到网络。(这一步会消耗以太币,还需要使用你的节点的默认地址或者指定地址来给合约签名。) => 获得合约的区块链地址和ABI(合约接口的JSON表示,包括变量,事件和可以调用的方法)。(译注:作者在这里把ABI与合约接口弄混了。ABI是合约接口的二进制表示。)
4 eb3.js提供的JavaScript API来调用合约。(根据调用的类型有可能会消耗以太币。)
部署合约
因为geth1.6版本以后都不支持solidity编译,所以我们在线编译以后再赋值给abi
> address = eth.accounts[0]
"0x8260b02ac49855f9c00ff4275dc5291300517e30"
> personal.unlockAccount(address)
Unlock account 0x8260b02ac49855f9c00ff4275dc5291300517e30
Passphrase:
true
部署合约就是将编译好的合约字节码通过外部账号发送交易的形式部署到以太坊区块链上。输入以下命令:
> abi = [{constant:false,inputs:{name:'a',type:'uint256'}}]
[{
constant: false,
inputs: {
name: "a",
type: "uint256"
}
}]
> MyContract = eth.contract(abi)
{
abi: [{
constant: false,
inputs: {
name: "a",
type: "uint256"
}
}],
eth: {
accounts: ["0x8260b02ac49855f9c00ff4275dc5291300517e30", "0xf7f54ba52d6226c1f3d4417cc0d700616474681d"],
blockNumber: 48,
coinbase: "0x8260b02ac49855f9c00ff4275dc5291300517e30",
compile: {
lll: function(),
serpent: function(),
solidity: function()
},
defaultAccount: undefined,
defaultBlock: "latest",
gasPrice: 18000000000,
hashrate: 0,
mining: false,
pendingTransactions: [],
protocolVersion: "0x3f",
syncing: false,
call: function(),
contract: function(abi),
estimateGas: function(),
filter: function(fil, callback),
getAccounts: function(callback),
getBalance: function(),
getBlock: function(),
getBlockNumber: function(callback),
getBlockTransactionCount: function(),
getBlockUncleCount: function(),
getCode: function(),
getCoinbase: function(callback),
getCompilers: function(),
getGasPrice: function(callback),
getHashrate: function(callback),
getMining: function(callback),
getPendingTransactions: function(callback),
getProtocolVersion: function(callback),
getRawTransaction: function(),
getRawTransactionFromBlock: function(),
getStorageAt: function(),
getSyncing: function(callback),
getTransaction: function(),
getTransactionCount: function(),
getTransactionFromBlock: function(),
getTransactionReceipt: function(),
getUncle: function(),
getWork: function(),
iban: function(iban),
icapNamereg: function(),
isSyncing: function(callback),
namereg: function(),
resend: function(),
sendIBANTransaction: function(),
sendRawTransaction: function(),
sendTransaction: function(),
sign: function(),
signTransaction: function(),
submitTransaction: function(),
submitWork: function()
},
at: function(address, callback),
getData: function(),
new: function()
}
> myContract = MyContract.new({from:address,data:"0x606060405260388060106000396000f3606060405260e060020a6000350463c6888fa18114601c575b6002565b3460025760076004350260408051918252519081900360200190f3"})
INFO [07-11|15:30:21] Submitted contract creation fullhash=0x20a00305a400a1a49faf48ca3cf3ec4a08d86b71063547ff30d3fa71ff13a255 contract=0x274bf7547c3e54a7fad23d4d3349e848ffb0a247
{
abi: [{
constant: false,
inputs: {
name: "a",
type: "uint256"
}
}],
address: undefined,
transactionHash: "0x20a00305a400a1a49faf48ca3cf3ec4a08d86b71063547ff30d3fa71ff13a255"
}
这时,我们可以检查一下交易池,查看当前交易的待处理状况:
> txpool.status
{
pending: 1,
queued: 0
}
我们可以看到当前的交易池中有一个交易正在等待确认。然后,我们查看待确认交易的详细内容:
> eth.getBlock("pending",true).transactions
[{
blockHash: "0x8889fa3b54432ceda35c280661f41887e37e6a26cfe8ebef4dc2cfe4c17270c4",
blockNumber: 49,
from: "0x8260b02ac49855f9c00ff4275dc5291300517e30",
gas: 90000,
gasPrice: 18000000000,
hash: "0x20a00305a400a1a49faf48ca3cf3ec4a08d86b71063547ff30d3fa71ff13a255",
input: "0x606060405260388060106000396000f3606060405260e060020a6000350463c6888fa18114601c575b6002565b3460025760076004350260408051918252519081900360200190f3",
nonce: 5,
r: "0x841832d644c4938e566d7faf18da1d27350421dbd880a1319de7533ad4d0a615",
s: "0x286bcf5d39af77ea7e446abf0e04a445cfacbf7ca103b5870a01bb106c4999e4",
to: null,
transactionIndex: 0,
v: "0x6096",
value: 0
}]
我们从显示出来的结果可以看出当前交易的一些内容。例如,from数据项就是我们发送交易的地址,input就是合约编译完成的字节码,这些内容均与我们之前的设定相同。而且,我们可以看到新的交易创建在第49区块中。
正在等待矿工的确认。
耐心等待一段时间,等待矿工确认完成后,我们再次使用txpool.status命令查看交易池的状态pending 为0
> miner.start()
> miner.stop()
我们发现交易池已经没有待确认的交易了。我们使用eth.getBlock(49令查看第294号区块的信息:
> eth.getBlock(49)
{
difficulty: 131072,
extraData: "0xd783010606846765746887676f312e382e31856c696e7578",
gasLimit: 4094191414,
gasUsed: 68946,
hash: "0x32fa4a3f8e767c90af33b5c70334995df08f973efd36959c212922f42f10eb10",
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
miner: "0x8260b02ac49855f9c00ff4275dc5291300517e30",
mixHash: "0x19418483843bd02fd570cbfb664fe53f6d3ed4b288f03d9963f933b78d55c315",
nonce: "0x47bed6e2b683c05f",
number: 49,
parentHash: "0x677e33fe6760aa95015016b6e57d1fd79d26dec50566354aad3eea851a6e03b7",
receiptsRoot: "0x9bf883aadf4abcf59e3a3cb48f93e179794d71b9889f547ded0fa182180a6b76",
sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
size: 698,
stateRoot: "0xa9093658ac11966f4329528efcb41c7a81a933032a9083e475aea2f9bbcd2254",
timestamp: 1499758299,
totalDifficulty: 6439680,
transactions: ["0x20a00305a400a1a49faf48ca3cf3ec4a08d86b71063547ff30d3fa71ff13a255"],
transactionsRoot: "0x61e4bd0c3840957155b91c1a6634f4466fe43d6295ab51481614c7b392adb5e2",
uncles: []
}
我们发现hash值为0x20a00305a400a1a49faf48ca3cf3ec4a08d86b71063547ff30d3fa71ff13a255的交易确实在第49区块中。
与合约交互
首先我们需要使用eth.contract来定义一个合约类,定义的合约类遵从ABI定义2:
> abiDefinition=[{ constant: false, inputs: [], name: "multiply", outputs: [], payable: false, type: "function" }]
[{
constant: false,
inputs: [],
name: "multiply",
outputs: [],
payable: false,
type: "function"
}]
然后得到合约实例:
> Multiply7 = eth.contract(abiDefinition)
{
abi: [{
constant: false,
inputs: [],
name: "multiply",
outputs: [],
payable: false,
type: "function"
}],
eth: {
accounts: ["0x8260b02ac49855f9c00ff4275dc5291300517e30", "0xf7f54ba52d6226c1f3d4417cc0d700616474681d"],
blockNumber: 54,
coinbase: "0x8260b02ac49855f9c00ff4275dc5291300517e30",
compile: {
lll: function(),
serpent: function(),
solidity: function()
},
defaultAccount: undefined,
defaultBlock: "latest",
gasPrice: 18000000000,
hashrate: 91,
mining: false,
pendingTransactions: [],
protocolVersion: "0x3f",
syncing: false,
call: function(),
contract: function(abi),
estimateGas: function(),
filter: function(fil, callback),
getAccounts: function(callback),
getBalance: function(),
getBlock: function(),
getBlockNumber: function(callback),
getBlockTransactionCount: function(),
getBlockUncleCount: function(),
getCode: function(),
getCoinbase: function(callback),
getCompilers: function(),
getGasPrice: function(callback),
getHashrate: function(callback),
getMining: function(callback),
getPendingTransactions: function(callback),
getProtocolVersion: function(callback),
getRawTransaction: function(),
getRawTransactionFromBlock: function(),
getStorageAt: function(),
getSyncing: function(callback),
getTransaction: function(),
getTransactionCount: function(),
getTransactionFromBlock: function(),
getTransactionReceipt: function(),
getUncle: function(),
getWork: function(),
iban: function(iban),
icapNamereg: function(),
isSyncing: function(callback),
namereg: function(),
resend: function(),
sendIBANTransaction: function(),
sendRawTransaction: function(),
sendTransaction: function(),
sign: function(),
signTransaction: function(),
submitTransaction: function(),
submitWork: function()
},
at: function(address, callback),
getData: function(),
new: function()
}
这里写代码片
> myMultiply7 = Multiply7.at(myContract.address)
{
abi: [{
constant: false,
inputs: [],
name: "multiply",
outputs: [],
payable: false,
type: "function"
}],
address: "0x274bf7547c3e54a7fad23d4d3349e848ffb0a247",
transactionHash: null,
allEvents: function(),
multiply: function()
}
我们可以看到,在实例中能够调用的函数有两个:allEvents和multiply。multiply显然是一开始我们定义合约的时候写的函数。我们可以使用两种方法来调用multiply函数:sendTransaction(3, {from: address})和call(3)。
> personal.unlockAccount(eth.accounts[0])
Unlock account 0x8260b02ac49855f9c00ff4275dc5291300517e30
Passphrase:
true
方法一:使用sendTransaction(3, {from: address})调用:
> myMultiply7.multiply.sendTransaction(3, {from:address})
INFO [07-11|15:36:48] Submitted transaction fullhash=0x68f1880a83eccdbe3bb1847deaae6a74df59d4ea8855368433e1af2c3d4c7f7a recipient=0x274bf7547c3e54a7fad23d4d3349e848ffb0a247
"0x68f1880a83eccdbe3bb1847deaae6a74df59d4ea8855368433e1af2c3d4c7f7a"
我们可以发现返回的值为一个字符串,这个字符串代表的是发送的交易的hash值。使用这个方法调用合约将会使调用的结果成为全局共识的一部分3。
方法二:使用call(3)调用:按理来说应该返回21,但是却返回为空,不知道是哪里出了问题
> myMultiply7.multiply.call(3)
[]