5分钟学会区块链 - 开发一条区块链 Develop BlockChain with Tendermint
本文攻略:解惑區(qū)塊鏈開發(fā),學習 Tendermint,給自己造一條區(qū)塊鏈
建議玩家等級:技術小白,學生黨,初級碼農
?
閱讀此文先解鎖技能:
實踐此文推薦裝備:
?
PART 1: Tendermint 是什么
上篇文章我們舉了雷布斯、杰克馬、坡尼馬和強東哥打麻將共同記賬的栗子,這回PO主見他們手寫記賬這么原始,就想給這四位寫一個區(qū)塊鏈記賬APP,讓他們從此告別手寫賬本。
既然重新造輪子這件事是不存在的,于是向大家介紹一款區(qū)塊鏈輪子叫 Tendermint(以下簡稱 TM),如果有玩家聽說過以太坊(Ethereum),這個什么坊有個分支 Ethermint 就是基于 TM 開發(fā)的,反正PO主只懂擼代碼不懂炒幣,不是很了解這到底是個什么工坊。
好了,先來了解一下 TM 的原理,因為實在沒什么可以可視化的 UI 讓玩家們一目了然。TM 主要包含兩部分:
那他兩到底干啥用的,說了半天好像還是不太理解,沒關系先記住他們,PO主剛開始看原文檔的時候也和各位玩家有著同樣的感受。
?
PART 2: Tendermint 安裝運行
1. 官方安裝指南
讓我們忽略更多的理論,直接擼起袖子做程序猿最喜歡做的事情,先下載輪子,命令行輸入:
go get github.com/Masterminds/glide go get github.com/tendermint/tendermint/cmd/tendermint下載過程比較長,這個輪子比較大(可能需要科學上網),下載完成后安裝,命令行輸入:
cd $GOPATH/src/github.com/tendermint/tendermint glide install go install ./cmd/tendermint安裝過程也比較長,安裝完成后驗證安裝是否成功,命令行輸入:
tendermint version abci-cli version截止本文的發(fā)表時間,tendermint 版本 0.15.0,abci-cli 版本 0.9.0
?
2. 運行官方栗子
官方文檔提供了兩個栗子,已經集成在了剛才的安裝里:
這里我們簡單介紹一下 dummy 這個栗子,首先啟動這個區(qū)塊鏈應用,命令行輸入:
abci-cli dummy然后啟動 TM,命令行輸入:
tendermint init tendermint node順利的話,可以看到 abci 和 tendermint 兩個程序連通(Connect)了,并且 tendermint 會像心跳一樣每一秒提交一個空區(qū)塊,我們接下來準備寫入有實質內容的新區(qū)塊,命令行輸入:
curl -s 'localhost:46657/broadcast_tx_commit?tx="abcd"' curl -s 'localhost:46657/broadcast_tx_commit?tx="name=satoshi"'我們的區(qū)塊鏈里就有了一個記錄“abcd”的區(qū)塊和另一個記錄“name=satoshi”的區(qū)塊,如果需要對區(qū)塊鏈內容進行查詢,命令行輸入:
curl -s 'localhost:46657/abci_query?data="name"' curl 是 Linux 常用工具,玩家可以通過網頁瀏覽器直接輸入 localhost:46657/abci_query?data="name"?
3. 探索官方工具
最后介紹 abci-cli 這個坑人工具登場,讓我們先關閉剛才運行的 dummy 應用和 tendermint,命令行重新輸入運行 dummy:
abci-cli dummy命令行再輸入:
abci-cli console然后他兩連通了(Connect),此時很多玩家會困惑于這兩個都叫 abci 的家伙怎么也能互相連通,abci 到底是個什么東西?他又干了什么?讓我們通過 PART 3 來重新梳理一下我們剛才究竟都在區(qū)塊鏈里的什么地方做了些什么事。
?
PART 3: Tendermint 再理解
PO主先把官方文檔里用的最多并容易讓人混淆的名詞都羅列出來:
然后總結了三個名詞來幫助理解,下文約定統(tǒng)一使用這三個名詞:
?
還是把栗子舉一舉,假設強東哥在使用我寫的的區(qū)塊鏈記賬 APP(用iOS開發(fā)的):
?
最后再總結幾點:
?
PART 4: 開發(fā)一條區(qū)塊鏈
總算到了擼代碼環(huán)節(jié),我們先把項目架構整理一下:
?
接下來正式擼代碼,我們主要講解一部分核心邏輯:
1. ClientApp
模擬了5個區(qū)塊,每個區(qū)塊記錄10條記錄,將這些記錄轉成 json 提交給 Tendermint
blocksNumber := 5 // how many blocks transactionsPerBlock := 10 // how many transactions in each block players := []string{"Lei", "Jack", "Pony", "Richard"} // 4 players random := rand.New(rand.NewSource(time.Now().UnixNano())) json := jsoniter.ConfigCompatibleWithStandardLibraryfor i := 0; i < blocksNumber; i++ {time.Sleep(time.Second * 1)transactions := []controllers.Transaction{}for j := 0; j < transactionsPerBlock; j++ {from := players[random.Intn(len(players))]to := players[random.Intn(len(players))]for from == to {to = players[random.Intn(len(players))]}btc := float32(random.Intn(10) + 1)tran := controllers.Transaction{From: from,To: to,Bitcoin: btc,}_, _ = tran.Create()transactions = append(transactions, tran)}bytes, _ := json.Marshal(&transactions)data := strings.Replace(string(bytes), "\"", "'", -1)tx := data// tmAsync(tx)tmCommit(tx) }?
func tmCommit(tx string) {url := "http://localhost:46657/broadcast_tx_async?tx=\"" + tx + "\""txHandle(url) }?
2. Tendermint
通過命令行運行一個定義好的 Shell 腳本,并且把運行結果打印到控制臺和日志文件中去
f, err := os.Create("logs/tendermint.log") if err != nil {fmt.Println("Tendermint log init error:", err) } multiWriter := io.MultiWriter(f, os.Stdout)go func() {cmd := exec.Command("bash", "-c", "sh run-tm.sh")cmd.Stdout = multiWritercmd.Start() }()run-tm.sh 腳本內容:
echo tendermint start tendermint init tendermint unsafe_reset_all tendermint node --consensus.create_empty_blocks=false echo tendermint end unsafe_reset_all 作用是每次重置本機的區(qū)塊鏈數據,僅供開發(fā)使用 consensus.create_empty_blocks 作用是關閉 Tendermint 自帶的每秒生成新的空區(qū)塊功能?
3. ABCI
實現(xiàn) ABCI 指令接口,這里我們直接使用了官方栗子 dummy 應用,來保存提交的 json 記錄,并且在每個實現(xiàn)接口里做了日志打印(因篇幅有限,省略了長長的代碼)
func (app *DummyApplication) CheckTx(tx []byte) types.ResponseCheckTx {lib.Log.Debug("CheckTx")lib.Log.Notice(string(tx))return types.ResponseCheckTx{Code: code.CodeTypeOK} }func (app *DummyApplication) DeliverTx(tx []byte) types.ResponseDeliverTx {lib.Log.Debug("DeliverTx")lib.Log.Notice(string(tx))// ...return types.ResponseDeliverTx{Code: code.CodeTypeOK, Tags: tags} }func (app *DummyApplication) Commit() types.ResponseCommit {lib.Log.Debug("Commit")// ...lib.Log.Debug("Commit Hash", hash)return types.ResponseCommit{Code: code.CodeTypeOK, Data: hash} }func (app *DummyApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {lib.Log.Debug("Query")// ... }?
4. 編譯
我們寫好了編譯腳本,命令行輸入:
sh make.sh編譯腳本本質就是把三個運行程序編譯出來:
go build ./TendermintApp/ABCIServer/ go build ./TendermintApp/ABCIClient/ go build -o Client ./ClientApp/?
5. 測試
到了激動人心的一刻,我們已經離一條自造的區(qū)塊鏈很接近了。
先運行 ABCI,命令行輸入:
./ABCIServer再運行 Tendermint,命令行輸入:
./ABCIClient可以看到 Tendermint 和 ABCI 已經有 3 個連接(Connect) Socket 握手了,表示整個區(qū)塊鏈服務已經準備就緒,最后我們只需要使用 Client 往區(qū)塊鏈里寫數據就行了,命令行輸入:
./Client把條命令理解成使用記賬 APP 記錄了 5 頁,每頁 10 條記錄,然后點擊保存后送去了區(qū)塊鏈。
?
附上一張運行結果圖,大致能觀察到三個程序都已成功運行
?
最終我們創(chuàng)造了一條區(qū)塊鏈,一共有 7 個區(qū)塊,2~6 號區(qū)塊各自寫有 10 條賬本記錄,第 1 和第 7 號區(qū)塊是系統(tǒng)創(chuàng)建的空區(qū)塊。
空區(qū)塊是怎么回事?原先 PO 主也以為是 BUG,去了官方的開發(fā) issue 里了解到 Tendermint 每次收到新的 tx 或者區(qū)塊鏈 hash 值變化的時候(就是區(qū)塊鏈狀態(tài)變了)會產生一個新區(qū)塊去接受 mempool 里未被提交的新 tx,這是 Tendermint 用于正常自檢工作產生的。?
來看看這條區(qū)塊鏈長什么樣子,這里展示了 2, 3, 4 號區(qū)塊的賬本記錄
?
感覺有好多$$在這小小的幾個區(qū)塊里,最后獻上本文代碼,希望各位玩家也創(chuàng)造一條屬于自己的區(qū)塊鏈。PO 主也默默去寫未完成的賬本 APP了。
https://zhuanlan.zhihu.com/p/33154604
總結
以上是生活随笔為你收集整理的5分钟学会区块链 - 开发一条区块链 Develop BlockChain with Tendermint的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Fcoin Token ( FT )——
- 下一篇: Ethermint部署及框架解析