以太坊私有链部署合约
以太坊私有链部署合约
1.建立私有链
[root@greg02 ~]#mkdir mychain
[root@greg02 ~]#cd mychain
[root@greg02 mychain]#geth --networkid 123 --dev --datadir data1 --rpc --rpcaddr 192.168.179.130 --rpcport 8989 --port 3000
#运行后产生如下文件
[root@greg02 mychain]#ls
data1
[root@greg02 mychain]#ls data1/
geth geth.ipc keystore
各项含义:
--identity:指定节点 ID;
--rpc:表示开启 HTTP-RPC 服务;
--rpcaddr:HTTP-RPC 服务ip地址;
--rpcport:指定 HTTP-RPC 服务监听端口号(默认为 8545);
--datadir:指定区块链数据的存储位置;
--port:指定和其他节点连接所用的端口号(默认为 30303);
--nodiscover:关闭节点发现机制,防止加入有同样初始配置的陌生节点。
保持节点的运行,不要关闭终端,重新打开一个终端,使用geth attach
连接节点,并且打开geth console
[root@greg02 mychain]#geth attach ipc:/root/mychain/data1/geth.ipc
Welcome to the Geth JavaScript console!
instance: Geth/v1.8.3-unstable-746392cf/linux-amd64/go1.9.2
coinbase: 0x804bf1ee046894d6425a8bed1abe553f776ae0df
at block: 0 (Thu, 01 Jan 1970 08:00:00 CST)
datadir: /root/mychain/data1
modules: admin:1.0 clique:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 shh:1.0 txpool:1.0 web3:1.0
>
这是一个交互式的 JavaScript 执行环境,在这里面可以执行 JavaScript 代码,其中 > 是命令提示符。在这个环境里也内置了一些用来操作以太坊的 JavaScript 对象,可以直接使用这些对象。这些对象主要包括:
eth:包含一些跟操作区块链相关的方法;
net:包含一些查看p2p网络状态的方法;
admin:包含一些与管理节点相关的方法;
miner:包含启动&停止挖矿的一些方法;
personal:主要包含一些管理账户的方法;
txpool:包含一些查看交易内存池的方法;
web3:包含了以上对象,还包含一些单位换算的方法。
2.创建账户
> personal.newAccount('grego')
"0x88d6725760f34a91059485e396759d422441e427"
> personal.listAccounts
["0x804bf1ee046894d6425a8bed1abe553f776ae0df"
> web3.eth.coinbase
"0x804bf1ee046894d6425a8bed1abe553f776ae0df"
3.编写只能合约
pragma solidity ^0.4.0;
contract Ballot {
struct Voter {
uint weight;
bool voted;
uint8 vote;
address delegate;
}
struct Proposal {
uint voteCount;
}
address chairperson;
mapping(address => Voter) voters;
Proposal[] proposals;
/// Create a new ballot with $(_numProposals) different proposals.
function Ballot(uint8 _numProposals) public {
chairperson = msg.sender;
voters[chairperson].weight = 1;
proposals.length = _numProposals;
}
/// Give $(toVoter) the right to vote on this ballot.
/// May only be called by $(chairperson).
function giveRightToVote(address toVoter) public {
if (msg.sender != chairperson || voters[toVoter].voted) return;
voters[toVoter].weight = 1;
}
/// Delegate your vote to the voter $(to).
function delegate(address to) public {
Voter storage sender = voters[msg.sender]; // assigns reference
if (sender.voted) return;
while (voters[to].delegate != address(0) && voters[to].delegate != msg.sender)
to = voters[to].delegate;
if (to == msg.sender) return;
sender.voted = true;
sender.delegate = to;
Voter storage delegateTo = voters[to];
if (delegateTo.voted)
proposals[delegateTo.vote].voteCount += sender.weight;
else
delegateTo.weight += sender.weight;
}
/// Give a single vote to proposal $(toProposal).
function vote(uint8 toProposal) public {
Voter storage sender = voters[msg.sender];
if (sender.voted || toProposal >= proposals.length) return;
sender.voted = true;
sender.vote = toProposal;
proposals[toProposal].voteCount += sender.weight;
}
function winningProposal() public constant returns (uint8 _winningProposal) {
uint256 winningVoteCount = 0;
for (uint8 prop = 0; prop < proposals.length; prop++)
if (proposals[prop].voteCount > winningVoteCount) {
winningVoteCount = proposals[prop].voteCount;
_winningProposal = prop;
}
}
}
BYTECODE:
ABI:
[
{
"constant": false,
"inputs": [
{
"name": "to",
"type": "address"
}
],
"name": "delegate",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "winningProposal",
"outputs": [
{
"name": "_winningProposal",
"type": "uint8"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "toVoter",
"type": "address"
}
],
"name": "giveRightToVote",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "toProposal",
"type": "uint8"
}
],
"name": "vote",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"name": "_numProposals",
"type": "uint8"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "constructor"
}
]
ABI删除空格并转义
[{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"}],\"name\":\"delegate\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"winningProposal\",\"outputs\":[{\"name\":\"_winningProposal\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"toVoter\",\"type\":\"address\"}],\"name\":\"giveRightToVote\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"toProposal\",\"type\":\"uint8\"}],\"name\":\"vote\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_numProposals\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}]
在console里创建ABI合约对象
> var abi=JSON.parse('[{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"}],\"name\":\"delegate\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"winningProposal\",\"outputs\":[{\"name\":\"_winningProposal\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"toVoter\",\"type\":\"address\"}],\"name\":\"giveRightToVote\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"toProposal\",\"type\":\"uint8\"}],\"name\":\"vote\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_numProposals\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}]')
undefined
> myContract=web3.eth.contract(abi)
{
abi: [{
constant: false,
inputs: [{...}],
name: "delegate",
outputs: [],
payable: false,
stateMutability: "nonpayable",
type: "function"
}, {
constant: true,
inputs: [],
name: "winningProposal",
outputs: [{...}],
payable: false,
stateMutability: "view",
type: "function"
}, {
constant: false,
inputs: [{...}],
name: "giveRightToVote",
outputs: [],
payable: false,
stateMutability: "nonpayable",
type: "function"
}, {
constant: false,
inputs: [{...}],
name: "vote",
outputs: [],
payable: false,
stateMutability: "nonpayable",
type: "function"
}, {
inputs: [{...}],
payable: false,
stateMutability: "nonpayable",
type: "constructor"
}],
eth: {
accounts: ["0x804bf1ee046894d6425a8bed1abe553f776ae0df", "0x88d6725760f34a91059485e396759d422441e427", "0x44d18ce9e2e54c93cf382e0a1e571e5e16173156"],
blockNumber: 0,
coinbase: "0x804bf1ee046894d6425a8bed1abe553f776ae0df",
compile: {
lll: function(),
serpent: function(),
solidity: function()
},
defaultAccount: undefined,
defaultBlock: "latest",
gasPrice: 1,
hashrate: 0,
mining: true,
pendingTransactions: [],
protocolVersion: "0x3f",
syncing: false,
call: function(),
contract: function(abi),
estimateGas: function(),
filter: function(options, callback, filterCreationErrorCallback),
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()
}
检查coinbase账号余额
> account1=web3.eth.coinbase
"0x804bf1ee046894d6425a8bed1abe553f776ae0df"
> web3.eth.getBalance(account1)
1.15792089237316195423570985008687907853269984665640564039457584007913129639927e+77
解锁coinbase账号
> web3.eth.coinbase
"0x804bf1ee046894d6425a8bed1abe553f776ae0df"
> personal.unlockAccount(account1, '')
true
BYTECODE预估费用
> web3.eth.estimateGas({data:bytecode})
597031
字节码前面需要添加0x
。手续费大概为597031``gas
部署合约
> contractInstance = myContract.new({data: bytecode gas: 1000000, from: account1}, function(e, contract){
...... if(!e){
......... if(!contract.address){
............ console.log("Contract transaction send: Transaction Hash: "+contract.transactionHash+" waiting to be mined...");
............ }else{
............ console.log("Contract mined! Address: "+contract.address);
............ console.log(contract);
............ }
......... }else{
......... console.log(e)
......... }
...... })
Contract transaction send: Transaction Hash: 0xca1561453f4cc9541ec84dd4ef3a25cbb61ef4d1e9bf1f829fef5107f9017266 waiting to be mined...
{
abi: [{
constant: false,
inputs: [{...}],
name: "delegate",
outputs: [],
payable: false,
stateMutability: "nonpayable",
type: "function"
}, {
constant: true,
inputs: [],
name: "winningProposal",
outputs: [{...}],
payable: false,
stateMutability: "view",
type: "function"
}, {
constant: false,
inputs: [{...}],
name: "giveRightToVote",
outputs: [],
payable: false,
stateMutability: "nonpayable",
type: "function"
}, {
constant: false,
inputs: [{...}],
name: "vote",
outputs: [],
payable: false,
stateMutability: "nonpayable",
type: "function"
}, {
inputs: [{...}],
payable: false,
stateMutability: "nonpayable",
type: "constructor"
}],
address: undefined,
transactionHash: "0xca1561453f4cc9541ec84dd4ef3a25cbb61ef4d1e9bf1f829fef5107f9017266"
}
合约等待挖矿
> miner.start()
null
> miner.stop()
true