上一篇文章说完Go语言开发区块链项目的技术原理,现在我们通过实际的Go语言代码,来看看使用Go语言怎么去实现这个简单的区块链项目。
这个区块链项目的工程目录设计如下:
-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实例,实际的区块链项目当然要比这个复杂的多,这里只是像通过这个实例来给大家分解一下它的技术原理,也希望这个实例能让大家更好的理解区块链技术。
版权声明:除特殊说明,文章均为博主 去吐槽 原创文章,转载请注明原文出处。