一、說明
想嘗試基於以太坊的應用或者Tokens發佈,無奈正常網絡測試需要用Ether,購買麻煩,各步驟還得需要消耗以太幣,不過我們可以搭建私有鏈來進行開發,話不多說,馬上開始搭建我們自己的開發測試私有鏈。
二、所需工具
-
以太坊客戶端
以太坊客戶端用於接入以太坊網絡,進行賬戶管理、交易、挖礦、智能合約相關的操作。目前有多種語言實現的客戶端,常用的有 Go 語言實現的 go-ethereum 客戶端 Geth,支持接入以太坊網絡併成爲一個完整節點,也可作爲一個 HTTP-RPC 服務器對外提供 JSON-RPC 接口。
其他的客戶端有:智能合約編譯器- Parity:Rust 語言實現;
- cpp-ethereum:C++ 語言實現;
- ethereumjs-lib:JavaScript 語言實現;
- Ethereum(J):Java 語言實現;
- ethereumH:Haskell 語言實現;
- pyethapp: Python 語言實現;
- ruby-ethereum:Ruby 語言實現;
-
以太坊支持兩種智能合約的編程語言:Solidity 和 Serpent。現在的主流是Solidity,學習教程可參考 站點。
現在以太坊提供更方便的在線 IDE —— Remix https://remix.ethereum.org 使用 Remix,免去了安裝
solc和編譯過程,它可以直接提供部署合約所需的二進制碼和 ABI。
-
以太坊錢包
以太坊提供了圖形界面的錢包 Ethereum Wallet 和 Mist Dapp 瀏覽器。錢包的功能是 Mist 的一個子集,可用於管理賬戶和交易;Mist 在錢包基礎上,還能操作智能合約。爲了演示合約部署過程,本文使用了 Geth console 操作,沒有用到 Mist,當然,使用 Mist 會更簡單。
三、安裝
服務器我們採用Ubuntu16.04。
首先安裝必要的工具
apt install software-properties-common
再次添加以太坊源
add-apt-repository -y ppa:ethereum/ethereum apt update
最後安裝go-ethereum
apt install ethereum
安裝完成後,可以運行命令查看是否成功
geth version
顯示
Geth Version: 1.8.2-stable Git Commit: b8b9f7f4476a30a0aaf6077daade6ae77f969960 Architecture: amd64 Protocol Versions: [63 62] Network Id: 1 Go Version: go1.9.4 Operating System: linux GOPATH= GOROOT=/usr/lib/go-1.9
四、私有鏈搭建
1、創建初始化配置文件和存放數據目錄
要運行以太坊私有鏈,需要定義自己創世區塊,創世區塊是一個json格式配置文件。我們可以新建一個文件 genesis.json
{ "config": { "chainId": 411, "homesteadBlock": 0, "eip155Block": 0, "eip158Block": 0 }, "nonce": "0x0000000000000033", "timestamp": "0x0", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "gasLimit": "0x8000000", "difficulty": "0x100", "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", "coinbase": "0x0000000000000000000000000000000000000000", "alloc": { "0x1C83C95473e1e93A2C8560c73976dAFA9C3f0a79":{"balance":"1000000"} } }
其中chainID 指定了區塊鏈網絡ID。
並且我對自己地址進行了配額。其他參數可參考 站點
存放數據目錄在此我使用 /home/ubuntu/ethereum/data0
genesis.json存放在/home/ubuntu/ethereum/
然後可以執行命令來進行初始化操作。
cd ethereum
geth --datadir data0 init genesis.json
結果
INFO [04-11|07:51:14] Maximum peer count ETH=25 LES=0 total=25 INFO [04-11|07:51:14] Allocated cache and file handles database=/home/ubuntu/ethereum/data0/geth/chaindata cache=16 handles=16 INFO [04-11|07:51:14] Writing custom genesis block INFO [04-11|07:51:14] Persisted trie from memory database nodes=1 size=195.00B time=35.174碌s gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B INFO [04-11|07:51:14] Successfully wrote genesis state database=chaindata hash=b924d6Ωfdceb INFO [04-11|07:51:14] Allocated cache and file handles database=/home/ubuntu/ethereum/data0/geth/lightchaindata cache=16 handles=16 INFO [04-11|07:51:14] Writing custom genesis block INFO [04-11|07:51:14] Persisted trie from memory database nodes=1 size=195.00B time=460.134碌s gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B INFO [04-11|07:51:14] Successfully wrote genesis state database=lightchaindata hash=b924d6Ωfdceb
初始化成功後,會在data0目錄下生產所需文件。
其中 geth/chaindata
中存放的是區塊數據,keystore
中存放的是賬戶數據。
五、啓動私有節點
初始化完成後,就有了一條自己的私有鏈。我們可以執行命令來啓動它
geth --identity "TestNode" --rpc --rpcport "8545" --datadir data0 --port "30303" --nodiscover console
上面命令的主體是 geth console
,表示啓動節點並進入交互式控制檯。
各選項含義如下:
- –identity:指定節點 ID;
- –rpc:表示開啓 HTTP-RPC 服務;
- –rpcport:指定 HTTP-RPC 服務監聽端口號(默認爲 8545);
- –datadir:指定區塊鏈數據的存儲位置;
- –port:指定和其他節點連接所用的端口號(默認爲 30303);
- –nodiscover:關閉節點發現機制,防止加入有同樣初始配置的陌生節點。
運行上面的命令後,就啓動了區塊鏈節點並進入了該節點的控制檯:
INFO [04-11|08:05:23] Maximum peer count ETH=25 LES=0 total=25 INFO [04-11|08:05:23] Starting peer-to-peer node instance=Geth/TestNode/v1.8.2-stable-b8b9f7f4/linux-amd64/go1.9.4 INFO [04-11|08:05:23] Allocated cache and file handles database=/home/ubuntu/ethereum/data0/data0/geth/chaindata cache=768 handles=512 INFO [04-11|08:05:23] Writing default main-net genesis block INFO [04-11|08:05:23] Persisted trie from memory database nodes=12356 size=2.34mB time=47.705254ms gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B INFO [04-11|08:05:23] Initialised chain configuration config="{ChainID: 1 Homestead: 1150000 DAO: 1920000 DAOSupport: true EIP150: 2463000 EIP155: 2675000 EIP158: 2675000 Byzantium: 4370000 Constantinople: <nil> Engine: ethash}" INFO [04-11|08:05:23] Disk storage enabled for ethash caches dir=/home/ubuntu/ethereum/data0/data0/geth/ethash count=3 INFO [04-11|08:05:23] Disk storage enabled for ethash DAGs dir=/root/.ethash count=2 INFO [04-11|08:05:23] Initialising Ethereum protocol versions="[63 62]" network=1 INFO [04-11|08:05:23] Loaded most recent local header number=0 hash=d4e567b8fa3 td=17179869184 INFO [04-11|08:05:23] Loaded most recent local full block number=0 hash=d4e567b8fa3 td=17179869184 INFO [04-11|08:05:23] Loaded most recent local fast block number=0 hash=d4e567b8fa3 td=17179869184 INFO [04-11|08:05:23] Regenerated local transaction journal transactions=0 accounts=0 INFO [04-11|08:05:23] Starting P2P networking INFO [04-11|08:05:23] RLPx listener up self="enode://b5e91ca148308d721599ac14b9f2a9aff28c88b258a439fbc19f094d65ecaa9954a6a7d0de29f5737726bcdb20a443db9edeedce0471c1ba5cda043e8601e0d0@[::]:30303?discport=0" INFO [04-11|08:05:23] IPC endpoint opened url=/home/ubuntu/ethereum/data0/data0/geth.ipc INFO [04-11|08:05:23] HTTP endpoint opened url=http://127.0.0.1:8545 cors= vhosts=localhost Welcome to the Geth JavaScript console! instance: Geth/TestNode/v1.8.2-stable-b8b9f7f4/linux-amd64/go1.9.4 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
這是一個交互式的 JavaScript 執行環境,在這裏面可以執行 JavaScript 代碼,其中 >
是命令提示符。在這個環境裏也內置了一些用來操作以太坊的 JavaScript 對象,可以直接使用這些對象。這些對象主要包括:
- eth:包含一些跟操作區塊鏈相關的方法;
- net:包含一些查看p2p網絡狀態的方法;
- admin:包含一些與管理節點相關的方法;
- miner:包含啓動&停止挖礦的一些方法;
- personal:主要包含一些管理賬戶的方法;
- txpool:包含一些查看交易內存池的方法;
- web3:包含了以上對象,還包含一些單位換算的方法。
六、控制檯操作
進入以太坊 Javascript Console 後,就可以使用裏面的內置對象做一些操作,這些內置對象提供的功能很豐富,比如查看區塊和交易、創建賬戶、挖礦、發送交易、部署智能合約等。
常用命令有:
- personal.newAccount():創建賬戶;
- personal.unlockAccount():解鎖賬戶;
- eth.accounts:枚舉系統中的賬戶;
- eth.getBalance():查看賬戶餘額,返回值的單位是 Wei(Wei 是以太坊中最小貨幣面額單位,類似比特幣中的
聰
,1 ether = 10^18 Wei); - eth.blockNumber:列出區塊總數;
- eth.getTransaction():獲取交易;
- eth.getBlock():獲取區塊;
- miner.start():開始挖礦;
- miner.stop():停止挖礦;
- web3.fromWei():Wei 換算成以太幣;
- web3.toWei():以太幣換算成 Wei;
- txpool.status:交易池中的狀態;
- admin.addPeer():連接到其他節點;
這些命令支持 Tab
鍵自動補全,具體用法如下。
1、創建賬戶
>personal.newAccount() Passphrase: Repeat passphrase: "0x914995c9c3c993c9d3fdd63602c91823f932b308"
同樣方法再創建一個
> personal.newAccount() Passphrase: Repeat passphrase: "0x30ed8cd207dfdaf5e24847252df822b1da1f2fe5"
> eth.accounts ["0x914995c9c3c993c9d3fdd63602c91823f932b308", "0x30ed8cd207dfdaf5e24847252df822b1da1f2fe5"]
2、查看賬戶餘額
eth.getBalance(eth.accounts[0])
3、啓動 停止挖礦
啓動挖礦
>miner.start(1)其中 start 的參數表示挖礦使用的線程數。第一次啓動挖礦會先生成挖礦所需的 DAG 文件,這個過程有點慢,等進度達到 100% 後,就會開始挖礦,此時屏幕會被挖礦信息刷屏。
停止挖礦
>miner.stop()挖到一個區塊會獎勵5個以太幣,挖礦所得的獎勵會進入礦工的賬戶,這個賬戶叫做 coinbase,默認情況下 coinbase 是本地賬戶中的第一個賬戶,可以通過 miner.setEtherbase() 將其他賬戶設置成 coinbase。
再次查看賬戶餘額
> eth.getBalance(eth.accounts[0]) 510000000000000000000
4、發送交易
目前,賬戶0已經挖到了97個塊的獎勵,賬戶1餘額還是0:
> eth.getBalance(eth.accounts[0]) 510000000000000000000 > eth.getBalance(eth.accounts[1]) 0我們要從賬戶0到賬戶1轉賬,需要先解鎖賬戶0才能轉賬
> personal.unlockAccount(eth.accounts[0]) Unlock account 0x914995c9c3c993c9d3fdd63602c91823f932b308 Passphrase: true轉賬0->1
> amount = web3.toWei(5,'ether') "5000000000000000000" > eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[1],value:amount}) INFO [04-11|09:37:09] Submitted transaction fullhash=0x2d8342ce23ca00a61a66a9926d45e8516bd0edda18703770c72897d2b9c31973 recipient=0x30Ed8Cd207dfdAF5E24847252DF822b1DA1F2FE5 "0x2d8342ce23ca00a61a66a9926d45e8516bd0edda18703770c72897d2b9c31973"
此時如果沒有挖礦,用 txpool.status
命令可以看到本地交易池中有一個待確認的交易,可以使用 eth.getBlock("pending", true).transactions
查看當前待確認交易。
> txpool.status { pending: 1, queued: 0 } > eth.getBlock("pending", true).transactions [{ blockHash: "0x2a13705bbe3a60c1d8fa686d6c8a326c6f1b70e7943bb7be8d8e9aa9fef7701e", blockNumber: 103, from: "0x914995c9c3c993c9d3fdd63602c91823f932b308", gas: 90000, gasPrice: 18000000000, hash: "0x2d8342ce23ca00a61a66a9926d45e8516bd0edda18703770c72897d2b9c31973", input: "0x", nonce: 0, r: "0x546055f53f1f7535549c4e31ddf03c6678384afc9571240d237823c205239a11", s: "0x65f39c6a35f338c6fe67faf7a3bb14c91abc0472113bb9916c82cc51a407f6c9", to: "0x30ed8cd207dfdaf5e24847252df822b1da1f2fe5", transactionIndex: 0, v: "0x359", value: 5000000000000000000 }]
使用 miner.start()
命令開始挖礦:
> miner.start(1);admin.sleepBlocks(1);miner.stop(); INFO [04-11|09:39:49] Updated mining threads threads=1 INFO [04-11|09:39:49] Transaction pool price threshold updated price=18000000000 INFO [04-11|09:39:49] Starting mining operation INFO [04-11|09:39:49] Commit new mining work number=103 txs=1 uncles=0 elapsed=378.402碌s INFO [04-11|09:39:52] Successfully sealed new block number=103 hash=8327606bec9 INFO [04-11|09:39:52] block reached canonical chain number=98 hash=9d43b286588 INFO [04-11|09:39:52] mined potential block number=103 hash=8327606bec9 INFO [04-11|09:39:52] Commit new mining work number=104 txs=0 uncles=0 elapsed=231.591碌s true
新區塊挖出後,挖礦結束,查看賬戶 1 的餘額,已經收到了賬戶 0 的以太幣:
> web3.fromWei(eth.getBalance(eth.accounts[1]),'ether') 5
5、查看交易和區塊
查看當前區塊總數:
> eth.blockNumber 103
通過交易 Hash 查看交易(Hash 值包含在上面交易返回值中):
> eth.getTransaction("0x2d8342ce23ca00a61a66a9926d45e8516bd0edda18703770c72897d2b9c31973") { blockHash: "0x83276067a8ad0168cf1d9fabb089b7778024bc6700434f470d830decb4a6bec9", blockNumber: 103, from: "0x914995c9c3c993c9d3fdd63602c91823f932b308", gas: 90000, gasPrice: 18000000000, hash: "0x2d8342ce23ca00a61a66a9926d45e8516bd0edda18703770c72897d2b9c31973", input: "0x", nonce: 0, r: "0x546055f53f1f7535549c4e31ddf03c6678384afc9571240d237823c205239a11", s: "0x65f39c6a35f338c6fe67faf7a3bb14c91abc0472113bb9916c82cc51a407f6c9", to: "0x30ed8cd207dfdaf5e24847252df822b1da1f2fe5", transactionIndex: 0, v: "0x359", value: 5000000000000000000 }
通過區塊號查看區塊
> eth.getBlock(102) { difficulty: 137514, extraData: "0xd783010802846765746887676f312e392e34856c696e7578", gasLimit: 121486905, gasUsed: 0, hash: "0x09c0a05f1a76fa39222f965d0b3665550bb5a0ab518963c8d1c5280a7b13cf43", logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", miner: "0x914995c9c3c993c9d3fdd63602c91823f932b308", mixHash: "0x7afd2e352e797ad57554bd81d1f156baed041242fcb641c336683fc9f5937b6c", nonce: "0x4fe257812731bb15", number: 102, parentHash: "0xaf1c22536346d8183b63632e4eb6fae81bfd5f9ca305f5fe20b9b7ef0da2a9de", receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", size: 536, stateRoot: "0x73bb0a88af2d04b4fcec031a48ffdc16cda90b88c215e3587f1e9acc1c050eca", timestamp: 1523438740, totalDifficulty: 13695386, transactions: [], transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", uncles: [] }