当前位置:   article > 正文

【区块链】Go 实现简单区块链_go 区块链

go 区块链

本文主要利用 Go 语言对区块链模型进行了简单的实现,通过 GoLand 创建链式结构和一个简单的 http server,对外暴露读写接口,运行 rpc 并以地址访问形式向区块链发送数据和读取数据。

简单区块链的实现大致步骤分为:

(1)创建 Block
(2)创建 Blockchain
(3)创建 Http server

在实现之前,首先通过 GoLand 创建 blockchainDemo 项目,并建立对应的 Block.goBlockchain.go 以及 Server.go 文件,具体的目录如下。

一、创建 Block

  • 创建 Block 文件
  • 创建 Block 结构体与相关函数
package core  
  
import (  
   "crypto/sha256"  
   "encoding/hex"   "time")  
  
type Block struct {  
   Index         int64  // 区块编号  
   Timestamp     int64  // 区块时间戳  
   PrevBlochHash string // 上一个区块哈希值  
   Hash          string // 当前区块哈希值  
  
   Data string // 区块数据  
}  
  
// calculateHash 计算哈希值  
func calculateHash(b Block) string {  
   blockData := string(b.Index) + string(b.Timestamp) + b.PrevBlochHash + b.Data  
   hashInBytes := sha256.Sum256([]byte(blockData))  
   return hex.EncodeToString(hashInBytes[:])  
}  
  
// GenerateNewBlock 创建新区块  
func GenerateNewBlock(preBlock Block, data string) Block {  
   newBlock := Block{}  
   newBlock.Index = preBlock.Index + 1  
   newBlock.PrevBlochHash = preBlock.Hash  
   newBlock.Timestamp = time.Now().Unix()  
   newBlock.Data = data  
   newBlock.Hash = calculateHash(newBlock)  
   return newBlock  
}  
  
// GenerateGenesisBlock 创建世纪区块  
func GenerateGenesisBlock() Block {  
   preBlock := Block{}  
   preBlock.Index = -1  
   preBlock.Hash = ""  
   return GenerateNewBlock(preBlock, "Genesis Block")  
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

这里需要注意的是,在创建世纪区块时,考虑到对 GenerateNewBlock 函数的复用,因此,创建了一个 preBlock 来辅助世纪块的创建,实际区块链上世纪块前面不存在其他区块,且世纪块以 0 作为索引。

二、创建 Blockchain

  • 创建 Blockchain 文件
  • 创建 Blockchain 结构体及相关方法
package core  
  
import (  
   "fmt"  
   "log")  
  
type Blockchain struct {  
   Blocks []*Block  
}  
  
// CreateBlockchain 创建区块链  
func CreateBlockchain() *Blockchain {  
   genesisBlock := GenerateGenesisBlock()  
   blockchain := Blockchain{}  
   blockchain.AppendBlock(&genesisBlock)  
   return &blockchain  
}  
  
// SendData 向区块链添加数据  
func (bc *Blockchain) SendData(data string) {  
   preBlock := bc.Blocks[len(bc.Blocks)-1]  
   newBlock := GenerateNewBlock(*preBlock, data)  
   bc.AppendBlock(&newBlock)  
}  
  
// AppendBlock 向区块链添加新区块  
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 isValid(newBlock Block, oldBlock Block) bool {  
   if newBlock.Index-1 != oldBlock.Index {  
      return false  
   }  
   if newBlock.PrevBlochHash != oldBlock.Hash {  
      return false  
   }  
   if calculateHash(newBlock) != newBlock.Hash {  
      return false  
   }  
   return true  
}  
  
// Print 对区块链上的区块内容进行打印  
func (bc *Blockchain) Print() {  
   for _, block := range bc.Blocks {  
      fmt.Printf("Index: %d\n", block.Index)  
      fmt.Printf("Prev.Hash: %s\n", block.PrevBlochHash)  
      fmt.Printf("Curr.Hash: %s\n", block.Hash)  
      fmt.Printf("Data: %s\n", block.Data)  
      fmt.Printf("Timestamp: %d\n", block.Timestamp)  
   }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

三、创建 Http server

  • 创建 http server
  • 提供 API 访问接口
package main  
  
import (  
   "blockchainDemo/core"  
   "encoding/json"   "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, err := json.Marshal(blockchain)  
   if err != nil {  
      http.Error(w, err.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.CreateBlockchain()  
   run()  
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

四、模型测试

在 GoLand 上运行 http server,从代码中可知监听端口为 8888,因此,读写操作对应的地址是:

  • http://localhost:8888/blockchain/get
  • http://localhost:8888/blockchain/write?data=Send 1 BTC to Me

参数 data 的内容可自定义

// 网页显示效果
{
	"Blocks":[
		{
			"Index":0,
			"Timestamp":1674227301,
			"PrevBlochHash":"",
			"Hash":"90d7d6d9adc8a6dd4eca1e30d8c1a8556a8e3e508da81f30a9e520c2ee7124b0",
			"Data":"Genesis Block"
		},
		{
			"Index":1,
			"Timestamp":1674227338,
			"PrevBlochHash":"90d7d6d9adc8a6dd4eca1e30d8c1a8556a8e3e508da81f30a9e520c2ee7124b0",
			"Hash":"1a7c54ce0eaba45d5591640925405d90e74d9da5fa919b4e6eefa2447b2a4fb0",
			"Data":"Send 1 BTC to Me"
		}
	]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/931492
推荐阅读
相关标签
  

闽ICP备14008679号