Go语言开发区块链项目的代码实例

上一篇文章说完Go语言开发区块链项目的技术原理,现在我们通过实际的Go语言代码,来看看使用Go语言怎么去实现这个简单的区块链项目。

%title插图%num

这个区块链项目的工程目录设计如下:

-demochain //项目名称
—-cmd // main函数,也就是交易执行的入口
—-core // 核心代码,建立创世区块,hash加密,产生新区块等
—-rpc // rpc远程过程调用,可供http远程调用

下面开始分解具体的Go语言代码。

首先是core路径地下包含了Block.go和Blockchain.go,Block.go用来产生创世区块,也就是第一个区块,还有hash加密:

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.TimeStamp = time.Now().Unix()
   newBlock.PrevBlockHash = preBlock.Hash
   newBlock.Data = data //这一句放到下面Hash赋值语句后面,则会报错"invalid block",啥原因?
   newBlock.Hash = calculateHash(newBlock)
   return newBlock
}

func GenerateGenesisBlock() Block {
   preBlock := Block{}
   preBlock.Index = -1
   preBlock.Hash = ""
   return GenerateNewBlock(preBlock, "Genesis Block")
}

Blockchain.go则用来生成新的区块:

package core

import (
   "fmt"
   "log"
)

type Blockchain struct {
   Blocks []*Block
}

func NewBlockchain() *Blockchain {
   genesisBlock := GenerateGenesisBlock()
   blockchain := Blockchain{}
   blockchain.ApendBlock(&genesisBlock)
   return &blockchain
}

func (bc *Blockchain) SendData(data string) {
   preBlock := bc.Blocks[len(bc.Blocks)-1]
   newBlock := GenerateNewBlock(*preBlock, data)
   bc.ApendBlock(&newBlock)
}

func (bc *Blockchain) ApendBlock(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("Prev.Hash: %s\n", block.PrevBlockHash)
      fmt.Printf("Curr.Hash: %s\n", block.Hash)
      fmt.Printf("Data: %s\n", block.Data)
      fmt.Printf("Timestamp: %d\n", block.TimeStamp)
      fmt.Println()
   }
}

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
}

rpc路径下的Server.go用于提供对外的rpc远程调用服务:

package main

//rpc 远程过程调用
import (
   "encoding/json"
   "git.study.io/gostudy/demochain/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) //指定http监听端口
}

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()
}

最后我们通过cmd路径下的main.go来执行这个区块链项目:

package main

import (
   core2 "git.study.io/gostudy/demochain/core"
)

func main() {
   bc := core2.NewBlockchain()
   bc.SendData("Send  1 BTC to Jacky")
   bc.SendData("Send 1 EOS to Jack")
   bc.Print()
}

执行完之后输出的结果如下:

Index: 0
Prev.Hash: 
Curr.Hash: 90d7d6d9adc8a6dd4eca1e30d8c1a8556a8e3e508da81f30a9e520c2ee7124b0
Data: Genesis Block
Timestamp: 1623899698

Index: 1
Prev.Hash: 90d7d6d9adc8a6dd4eca1e30d8c1a8556a8e3e508da81f30a9e520c2ee7124b0
Curr.Hash: 0675102103c68c114db2e83c0ef70c3cb1db7d726d8631e80fc962047f68c53f
Data: Send 1 BTC to Jacky
Timestamp: 1623899698

Index: 2
Prev.Hash: 0675102103c68c114db2e83c0ef70c3cb1db7d726d8631e80fc962047f68c53f
Curr.Hash: a30bb3c1507015f4edcaaae839de7029398070a4d6c4e52a186a159c38ab21aa
Data: Send 1 EOS to Jack
Timestamp: 1623899698

上面结果中的Index: 0 就是创世区块,也就是第一个区块,每次运行一次交易都会生成一个新的区块,因为在main.go中执行了两次交易,所以从结果可以看出在创世区块之后创建了两个新的区块。

这是一个非常简单的基于Go语言来实现区块链技术的demo实例,实际的区块链项目当然要比这个复杂的多,这里只是像通过这个实例来给大家分解一下它的技术原理,也希望这个实例能让大家更好的理解区块链技术。

相关文章 推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注