以太坊私網(wǎng)建立 、合約編譯、部署完全教程(1)

一、為什么用到私有鏈?

在以太坊的共有鏈上部署智能合約、發(fā)起交易需要花費以太幣。而通過修改配置,可以在本機(jī)搭建一套以太坊私有鏈,因為與公有鏈沒關(guān)系,既不用同步公有鏈龐大的數(shù)據(jù),也不用花錢購買以太幣,很好地滿足了智能合約開發(fā)和測試的要求,開發(fā)好的智能合約也可以很容易地切換接口部署到以太坊公有鏈上。

二、開源工具和語言

1、brewMacOS包管理器

拷貝下面的命令到終端,然后回車。

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

2、install Go compiler

liyuechun:Downloads yuechunli$ brew install go

3、geth運(yùn)行以太坊節(jié)點

下載Source code (tar.gz)

liyuechun:Downloads yuechunli$ cd go-ethereum-1.5.9
liyuechun:go-ethereum-1.5.9 yuechunli$ pwd
/Users/liyuechun/Downloads/go-ethereum-1.5.9
liyuechun:go-ethereum-1.5.9 yuechunli$ make geth

4、Solidity以太坊智能合約語言

brew update
brew upgrade
brew tap ethereum/ethereum
brew install solidity
brew linkapps solidity

備注:安裝時間可能有點長,請耐心等待...
備注:安裝時間可能有點長,請耐心等待...
備注:安裝時間可能有點長,請耐心等待...

如果碰見下面的錯誤,請移步:http://blog.csdn.net/Sico2Sico/article/details/71082130

The GitHub credentials in the macOS keychain may be invalid.
Clear them with:
  printf "protocol=https\nhost=github.com\n" | git credential-osxkeychain erase
Or create a personal access token:
  https://github.com/settings/tokens/new?scopes=gist,public_repo&description=Homebrew

三、建立私鏈

1. 創(chuàng)建一個文件夾來存儲你的私鏈數(shù)據(jù)

liyuechun:1015 yuechunli$ mkdir privatechain
liyuechun:1015 yuechunli$ pwd
/Users/liyuechun/Desktop/1015
liyuechun:1015 yuechunli$ ls
privatechain
liyuechun:1015 yuechunli$ 

2. 使用geth來加載

geth --networkid 123 --dev --datadir data1 --rpc --rpcaddr 192.168.1.5 --rpcport 8989 --port 3000

各選項含義如下:

  • --identity:指定節(jié)點 ID;
  • --rpc:表示開啟 HTTP-RPC 服務(wù);
  • --rpcaddr:HTTP-RPC 服務(wù)ip地址;
  • --rpcport:指定 HTTP-RPC 服務(wù)監(jiān)聽端口號(默認(rèn)為 8545);
  • --datadir:指定區(qū)塊鏈數(shù)據(jù)的存儲位置;
  • --port:指定和其他節(jié)點連接所用的端口號(默認(rèn)為 30303);
  • --nodiscover:關(guān)閉節(jié)點發(fā)現(xiàn)機(jī)制,防止加入有同樣初始配置的陌生節(jié)點。

執(zhí)行上面的命令,你應(yīng)該能看到下面的信息:

INFO [10-15|03:14:50] IPC endpoint opened: /Users/liyuechun/Desktop/1015/privchain/geth.ipc
INFO [10-15|03:14:50] HTTP endpoint opened: http://127.0.0.1:8545

如果你切換到privchain文件夾里面,你會看到geth, geth.ipc, 和 keystore。

liyuechun:1015 yuechunli$ cd data1/
liyuechun:data1 yuechunli$ ls
geth        geth.ipc    keystore
liyuechun:data1 yuechunli$ 
  • 保持節(jié)點的運(yùn)行,不要關(guān)閉終端,重新打開一個終端,使用geth attach連接節(jié)點,并且打開geth console
liyuechun:privchain yuechunli$ geth attach ipc:/Users/liyuechun/Desktop/1015/privchain/geth.ipc 
Welcome to the Geth JavaScript console!

instance: Geth/v1.7.1-stable-05101641/darwin-amd64/go1.9.1
 modules: admin: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 執(zhí)行環(huán)境,在這里面可以執(zhí)行 JavaScript 代碼,其中 > 是命令提示符。在這個環(huán)境里也內(nèi)置了一些用來操作以太坊的 JavaScript 對象,可以直接使用這些對象。這些對象主要包括:

  • eth:包含一些跟操作區(qū)塊鏈相關(guān)的方法;
  • net:包含一些查看p2p網(wǎng)絡(luò)狀態(tài)的方法;
  • admin:包含一些與管理節(jié)點相關(guān)的方法;
  • miner:包含啟動&停止挖礦的一些方法;
  • personal:主要包含一些管理賬戶的方法;
  • txpool:包含一些查看交易內(nèi)存池的方法;
  • web3:包含了以上對象,還包含一些單位換算的方法。

3. 相關(guān)api命令

查看賬戶

> personal.listAccounts
[]
> 

創(chuàng)建賬戶

> personal.newAccount('liyuechun') 
"0xb6d7d842e7dc9016fa6900a183b2be26fc90b2d8"
> 

PS:里面的liyuechun是你賬戶的密碼,輸入你自己喜歡的密碼。

查看賬戶

> personal.listAccounts 
["0xb6d7d842e7dc9016fa6900a183b2be26fc90b2d8"]
> 

4. web3命令

https://ethereumbuilders.gitbooks.io/guide/content/en/ethereum_javascript_api.html

> web3.eth.coinbase 
"0xb6d7d842e7dc9016fa6900a183b2be26fc90b2d8"
> 

5. 編寫智能合約代碼

pragma solidity ^0.4.18;

contract test { 
    
    function multiply(uint a) returns(uint d){
        
        return a * 7;
    }
    
}

6. 獲取智能合約字節(jié)碼和abi

代碼拷貝到https://remix.ethereum.org,編譯,然后拷貝字節(jié)碼和ABI。

  • 字節(jié)碼
6060604052341561000f57600080fd5b5b60ab8061001e6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa114603d575b600080fd5b3415604757600080fd5b605b60048080359060200190919050506071565b6040518082815260200191505060405180910390f35b60006007820290505b9190505600a165627a7a7230582067d7c851e14e862886b6f53dad6825135557fb3a4b691350c94ea5b80605f6770029
  • ABI
[
  {
    "constant": true,
    "inputs": [
      {
        "name": "a",
        "type": "uint256"
      }
    ],
    "name": "multiply",
    "outputs": [
      {
        "name": "d",
        "type": "uint256"
      }
    ],
    "payable": false,
    "type": "function",
    "stateMutability": "view"
  }
]

7. 在bejson中轉(zhuǎn)義成字符串

http://www.bejson.com

[{\"constant\":true,\"inputs\":[{\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"multiply\",\"outputs\":[{\"name\":\"d\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\",\"stateMutability\":\"view\"}]

7. 通過abi創(chuàng)建合約對象

> var abi = JSON.parse('[{\"constant\":true,\"inputs\":[{\"name\":\"a\",\"type\":\"uint256\"}],\"name\":\"multiply\",\"outputs\":[{\"name\":\"d\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\",\"stateMutability\":\"view\"}]')
> myContract = web3.eth.contract(abi)
{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "multiply",
      outputs: [{...}],
      payable: false,
      type: "function"
  }],
  eth: {
    accounts: ["0x2abf46d8b0d940cdeedd55872bc0648add40227d"],
    blockNumber: 384,
    coinbase: "0x2abf46d8b0d940cdeedd55872bc0648add40227d",
    compile: {
      lll: function(),
      serpent: function(),
      solidity: function()
    },
    defaultAccount: undefined,
    defaultBlock: "latest",
    gasPrice: 0,
    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()
}

8. 檢查coinbase賬號余額

> account1 = web3.eth.coinbase
"0x2abf46d8b0d940cdeedd55872bc0648add40227d"
> web3.eth.getBalance(account1)
0
> 

如果余額大于0,繼續(xù),否則,開始挖礦。

> miner.start();
null
> 

挖礦過程中,切換到節(jié)點終端,你會發(fā)現(xiàn)一直在挖礦。

挖礦

如果你覺得差不多了,可以運(yùn)行下面的命令停止挖礦。

miner.stop();

9. 停止挖礦,并且查余額

> miner.start();
null
> miner.stop();
true
> web3.eth.getBalance(account1)
1.152e+21
> 

10. 解鎖coinbase賬號,我們通過coinbase賬號來付費部署合約

liyuechun: 換成你的密碼。

> personal.unlockAccount(account1, 'liyuechun') 
true
> 

11. 預(yù)估手續(xù)費

> bytecode = "6060604052341561000f57600080fd5b5b60ab8061001e6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa114603d575b600080fd5b3415604757600080fd5b605b60048080359060200190919050506071565b6040518082815260200191505060405180910390f35b60006007820290505b9190505600a165627a7a7230582067d7c851e14e862886b6f53dad6825135557fb3a4b691350c94ea5b80605f6770029"
"6060604052341561000f57600080fd5b5b60ab8061001e6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa114603d575b600080fd5b3415604757600080fd5b605b60048080359060200190919050506071565b6040518082815260200191505060405180910390f35b60006007820290505b9190505600a165627a7a7230582067d7c851e14e862886b6f53dad6825135557fb3a4b691350c94ea5b80605f6770029"
> web3.eth.estimateGas({data: bytecode})
Error: invalid argument 0: json: cannot unmarshal hex string without 0x prefix into Go struct field CallArgs.data of type hexutil.Bytes
    at web3.js:3104:20
    at web3.js:6191:15
    at web3.js:5004:36
    at <anonymous>:1:1

> bytecode = "0x6060604052341561000f57600080fd5b5b60ab8061001e6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa114603d575b600080fd5b3415604757600080fd5b605b60048080359060200190919050506071565b6040518082815260200191505060405180910390f35b60006007820290505b9190505600a165627a7a7230582067d7c851e14e862886b6f53dad6825135557fb3a4b691350c94ea5b80605f6770029"
"0x6060604052341561000f57600080fd5b5b60ab8061001e6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa114603d575b600080fd5b3415604757600080fd5b605b60048080359060200190919050506071565b6040518082815260200191505060405180910390f35b60006007820290505b9190505600a165627a7a7230582067d7c851e14e862886b6f53dad6825135557fb3a4b691350c94ea5b80605f6770029"
> web3.eth.estimateGas({data: bytecode})
98391
> 

備注:字節(jié)碼前面需要添加0x。手續(xù)費大概為98391``gas。

12. 部署合約,為了方便理解,設(shè)置一個回調(diào)函數(shù)

> contractInstance = contract.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: 0x5e2aebbf400d71a32e807dc3f11f1053b6ee3b2a81435ed8ace2fa54eebb9f3d waiting to be mined...
{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "multiply",
      outputs: [{...}],
      payable: false,
      type: "function"
  }],
  address: undefined,
  transactionHash: "0x5e2aebbf400d71a32e807dc3f11f1053b6ee3b2a81435ed8ace2fa54eebb9f3d"
}
> 

13. 你的合約等待挖礦,開始挖礦,等一會兒,停止

> miner.start()
null
> Contract mined! Address: 0xbf8b24283f2516360d3a4ba1db0df78ae74689db
[object Object]
> miner.stop()
true
> 
image

14. 檢查合約是否部署成功

> eth.getCode(contractInstance.address)
"0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa114603d575b600080fd5b3415604757600080fd5b605b60048080359060200190919050506071565b6040518082815260200191505060405180910390f35b60006007820290505b9190505600a165627a7a7230582067d7c851e14e862886b6f53dad6825135557fb3a4b691350c94ea5b80605f6770029"
> 

15. 調(diào)用合約方法

> contractInstance.multiply(6)
42
> 

PS: 這里添加call的原因是因為multiply函數(shù)沒有添加constant。

pragma solidity ^0.4.4;

contract test {

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

        return a * 7;
    }

}

Over Game!!!!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容