赞
踩
学习目标:1、理解什么是区块链;2、掌握区块链基本结构;3、构建区块链基本模型;
开发环境:GoLand (付费,学生可以申请免费,需要提供证明)
区块链的理论基础部分可以参考我写的其他博客,本文主要介绍实践。
开源代码:https://github.com/hexbo/go-blockchain-demo
如果有帮助欢迎star和分享~也欢迎提pr
hash函数的特点:单向性、确定性、隐蔽性、抗篡改、抗碰撞;
区块链最基本的技术是hash,这里给出用go写的一个hash的demo:
package main import ( "crypto/sha256" "encoding/hex" "log" ) func calcHash(toBeHashed string) string { hashInBytes := sha256.Sum256([]byte(toBeHashed)) hashInStr := hex.EncodeToString(hashInBytes[:]) log.Printf("%s %s", toBeHashed, hashInStr) return hashInStr } func main() { calcHash("test1") }
如果不熟悉Go,关于上述代码可能会有以下问题:
Go语言字符串string
和字节数组[]byte
类型转换问题:【Golang】字符咋存?utf8咋编码?string啥结构?、golang中字符串与数组,切片的转换
Go语言数组、切片的转换问题:数组和切片的相互转换
说明:sha256返回的是[32]byte,通过hashInBytes[:]将数组类型转为slice即[]byte
Go语言数组/切片传参问题:【Go基础】Go中数组传参的几种方式、Golang 数组(切片)的值传递与引用传递
组成部分:1.实现区块和链式结构;2.实现一个简单的HTTP Server,对外暴露读写接口;
说明:Go语言函数名大小写:小写代表方法只能在当前包使用,是私有方法,大写代表公有方法。
package core import ( "crypto/sha256" "encoding/hex" "time" ) type Block struct { Index int64 // 区块编号 Timestamp int64 // 区块时间戳 PrevBlockHash string // 上一个区块哈希值 Hash string // 当前区块哈希 Data string // 区块数据 } func calculateHash(b Block) string { blockData := string(b.Index) + string(b.Timestamp) + b.PrevBlockHash + b.Data hashInBytes := sha256.Sum256([]byte(blockData)) return hex.EncodeToString(hashInBytes[:]) } func GenerateNewBlock(preBlock Block, data string) Block { newBlock := Block{} newBlock.Index = preBlock.Index + 1 newBlock.PrevBlockHash = preBlock.Hash newBlock.Timestamp = time.Now().Unix() newBlock.Data = data newBlock.Hash = calculateHash(newBlock) return newBlock } func GenerateGenesisBlock() Block { preBlock := Block{} preBlock.Index = -1 preBlock.Hash = "" return GenerateNewBlock(preBlock, "Genesis Block") }
代码说明:参数名在函数前是结构函数的语法,类似C++的类成员函数,GO里都是绑定到结构体上的。
package core import ( "fmt" "log" ) type Blockchain struct { Blocks []*Block } func NewBlockchain() *Blockchain { genesisBlock := GenerateGenesisBlock() blockchain := Blockchain{} blockchain.AppendBlock(&genesisBlock) return &blockchain } func (bc *Blockchain) SendData(data string) { preBlock := bc.Blocks[len(bc.Blocks)-1] newBlock := GenerateNewBlock(*preBlock, data) bc.AppendBlock(&newBlock) } func (bc *Blockchain) AppendBlock(newBlock *Block) { if len(bc.Blocks) == 0 { bc.Blocks = append(bc.Blocks, newBlock) return } if isValid(*newBlock, *bc.Blocks[len(bc.Blocks)-1]) { bc.Blocks = append(bc.Blocks, newBlock) } else { log.Fatal("invalid block") } } func (bc *Blockchain) Print() { for _, block := range bc.Blocks { fmt.Printf("Index: %d\n", block.Index) fmt.Printf("PrevHash: %s\n", block.PrevBlockHash) fmt.Printf("CurrHash: %s\n", block.Hash) fmt.Printf("Data: %s\n", block.Data) fmt.Printf("Timestamp: %d\n", block.Timestamp) } } func isValid(newBlock Block, oldBlock Block) bool { if newBlock.Index-1 != oldBlock.Index { return false } if newBlock.PrevBlockHash != oldBlock.Hash { return false } if calculateHash(newBlock) != newBlock.Hash { return false } return true }
【问题】如下代码: 这里的len函数在这里不会冗余吗?
C的strlen需要对char数组遍历一遍,因此相当于O(n)的复杂度,不是O(1),不清楚Go的len函数
if isValid(*newBlock, *bc.Blocks[len(bc.Blocks)-1]) {
说明:参考上面给出的一个关于go string存储的问题,go在字符串指针开头存了字符串长度数据,而不是在末尾存’\0’,所以应该是可以O(1)查询。
package main
import "go-blockchain/core"
func main() {
bc := core.NewBlockchain()
bc.SendData("Send 1 BTC to Alice")
bc.SendData("Send 1 EOS to Bob")
bc.Print()
}
package main import ( "encoding/json" "go-blockchain/core" "io" "net/http" ) var blockchain *core.Blockchain func run() { http.HandleFunc("/blockchain/get", blockchainGetHandler) http.HandleFunc("/blockchain/write", blockchainWriteHandler) http.ListenAndServe("localhost:8888", nil) } func blockchainGetHandler(w http.ResponseWriter, r *http.Request) { bytes, error := json.Marshal(blockchain) if error != nil { http.Error(w, error.Error(), http.StatusInternalServerError) return } io.WriteString(w, string(bytes)) } func blockchainWriteHandler(w http.ResponseWriter, r *http.Request) { blockData := r.URL.Query().Get("data") blockchain.SendData(blockData) blockchainGetHandler(w, r) } func main() { blockchain = core.NewBlockchain() run() }
运行后访问localhost:8888/blockchain/get可以查看当前区块数据,访问/write?data="xxxx"可以写数据
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。