準備工作:
-
安裝go開發(fā)環(huán)境
-
用go搭建web服務(wù)
-
go語言基礎(chǔ)
安裝go開發(fā)環(huán)境
到https://golang.org/dl/這個地址下載對應(yīng)的安裝包,mac ,windows,linux都有(需要科學(xué)上網(wǎng))。以mac為例,下載成功后雙擊安裝下一步即可,很簡單。安裝成功后運行g(shù)o version查看版本(如果沒有的話,就重啟一下終端)
用go搭建web服務(wù)
在這里咱們用的是Gorilla/mux包。步驟:
-
創(chuàng)建NewRouter
-
設(shè)置端口號
-
設(shè)置http的參數(shù)字典
-
調(diào)用ListenAndServe方法,啟動服務(wù)
go語言基礎(chǔ)
-
導(dǎo)包:多個包用小括號括起來
-
import (
"sync"
"time"
)
-
使用點調(diào)用方法:
-
time.Now()
-
聲明變量:
-
var coin int 用空格隔開,類型寫到后面,變量名寫中間,最后是個var
-
coin := 10 也可以省略var,用:=來賦值,但是必須保證coin沒有聲明過,否則會報錯
-
coin1,coin2 := 10,20 。 多變量聲明是這樣的
-
條件控制:
-
if a<b {
return 10
}else{
return 20
}
-
循環(huán)控制:
-
for a := 0; a < 10; a++ {
fmt.Printf("a: %d ", a)
}
-
函數(shù)定義,傳參:
-
/* 函數(shù)返回兩個數(shù)的最大值 */
-
func max(num1, num2 int) int {
}
-
num1, num2 int表示兩個整形參數(shù),是可選的,也可以不填,
-
最后的int是返回值的類型
-
調(diào)用函數(shù)通過這樣方式:n := max(a, b)
-
結(jié)構(gòu)體定義,賦值,調(diào)用:
-
定義:type Article struct { title string id int}
-
賦值:var a1 Article
a1.title = "寫代碼"
-
調(diào)用:fmt.Printf( "title : %s ", a1.title)
了解這些,今天的代碼就能看懂了,當然go語言還有很多要學(xué)習(xí)的知識點,可以到這里來http://www.runoob.com/go/go-tutorial.html學(xué)習(xí)
整理思路:
根據(jù)之前了解的區(qū)塊鏈原理和共識算法,我們整理一下需要實現(xiàn)哪些方法:
-
一個區(qū)塊需要包含哪些信息:
-
Index :這個區(qū)塊在整個鏈中的索引
-
Timestamp : 區(qū)塊生成時的時間戳
-
Hash : 區(qū)塊通過 SHA256 算法生成的哈希值
-
PrevHash : 前一個區(qū)塊的 SHA256 哈希值
-
content : 需要記錄的內(nèi)容
-
計算哈希值的函數(shù)
-
生成新區(qū)塊的函數(shù)
-
根據(jù)不可篡改性,我們還需要一個驗證區(qū)塊是否被篡改的函數(shù)
-
啟動web服務(wù)的函數(shù)
創(chuàng)建區(qū)塊結(jié)構(gòu)體:
type Block struct {
Index int
Timestamp string
Content string
Hash string
PrevHash string
}
計算哈希值:(把區(qū)塊結(jié)構(gòu)體中的信息都拼在一起,然后Hash算出來)
func calculateHash(block Block) string {
record := strconv.Itoa(block.Index) + block.Timestamp + strconv.Itoa(block.Content) + block.PrevHash
h := sha256.New()
h.Write([]byte(record))
hashed := h.Sum(nil)
return hex.EncodeToString(hashed)
}
生成新區(qū)塊:(上一個區(qū)塊的索引加1,上一個區(qū)塊的Hash賦值給當前區(qū)塊的PrevHash,當前區(qū)塊的Hash由calculateHash函數(shù)生成)
func generateBlock(oldBlock Block, Content string) Block {
var newBlock Block
t := time.Now()
newBlock.Index = oldBlock.Index + 1
newBlock.Timestamp = t.String()
newBlock.Content = Content
newBlock.PrevHash = oldBlock.Hash
newBlock.Hash = calculateHash(newBlock)
return newBlock
}
驗證區(qū)塊:(根據(jù)索引和Hash值判斷,老索引加1應(yīng)該等于新索引,新的PrevHash應(yīng)該等于老的Hash,最后還要重新計算一個新區(qū)塊的Hash,看是否和傳過來的一樣)
func isBlockValid(newBlock, oldBlock Block) bool {
if oldBlock.Index+1 != newBlock.Index {
return false
}
if oldBlock.Hash != newBlock.PrevHash {
return false
}
if calculateHash(newBlock) != newBlock.Hash {
return false
}
return true
}
啟動web服務(wù):
//設(shè)置http需要的參數(shù),并開啟服務(wù)
func run() error {
mux := makeMuxRouter()
httpAddr := os.Getenv("ADDR")
log.Println("Listening on ", os.Getenv("ADDR"))
s := &http.Server{
Addr: ":" + httpAddr,
Handler: mux,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
if err := s.ListenAndServe(); err != nil {
return err
}
return nil
}
//生成NewRouter對象
func makeMuxRouter() http.Handler {
muxRouter := mux.NewRouter()
muxRouter.HandleFunc("/", handleGetBlockchain).Methods("GET")
muxRouter.HandleFunc("/", handleWriteBlock).Methods("POST")
return muxRouter
}
好的,需要的函數(shù)都已經(jīng)列好,下面把它們組裝起來即可,然后放到一個main.go的文件中,啟動終端,進入到main.go文件夾并輸入go run main.go命令。
打開http://localhost:8080/地址,會看到一個創(chuàng)世區(qū)塊,如果想添加一個新區(qū)塊則需要使用postman 傳一個content參數(shù)過去,如圖:
然后再刷新瀏覽器,會返回新的區(qū)塊信息,如圖:
好的,先到這里,下一次我們把共識算法加進去。
總結(jié):
今天實現(xiàn)了生成新區(qū)塊、哈希計算、區(qū)塊校驗這些基本功能。代碼在:https://github.com/sunqichao/createblockchain