1.项目文件创建
- 首先创建demochain目录,在该目录下创建两个目录,分别是blc目录,和server目录
- 在blc中创建两个文件,分别是Block.go和Blockchain.go
- 在server中创建一个Server.go
2.代码阶段
- Block.go中的代码如下:
package blc
import (
"crypto/sha256"
"encoding/hex"
"time"
)
//定义一个区块的结构体
type Block struct{
Index int64 //区块编号
Timestamp int64 //区块时间戳
PrevBlockHash string//上一个区块的哈希值
Hash string //当前区块哈希值
Data string //区块数据
}
//计算区块hash值
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 {
generBlock := Block{}
generBlock.Index = 0
generBlock.Hash = "0x0000000000000000000000000000000000000000000000000000000000000000"
return generateNewBlock(generBlock,"Genesis Block")
}
- Blockchain.go中的代码如下:
package blc
import (
"log"
)
//定义一个区块链的结构体
type Blockchain struct {
Blocks []*Block
}
//创建一个新的区块链
func NewBlockchain() *Blockchain {
genesisBlcok := generateGenesisBlock()
blockchain := Blockchain{}
blockchain.AppendBlock(&genesisBlcok)
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 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
}
- Server.go中的代码如下:
package main
import (
"demochain/blc"
"encoding/json"
"io"
"net/http"
)
var blockchain *blc.Blockchain
func run(){
//获取链上的数据
http.HandleFunc("/blockchain/get", blockchainGetHandler)
//写数据到链上
http.HandleFunc("/blockchain/write", blockchainWriteHandler)
//启动对端口的监听
http.ListenAndServe("localhost:8080", nil)
}
//获取链上的数据
func blockchainGetHandler(w http.ResponseWriter, r *http.Request){
//转化为json数据格式
bytes, error := json.Marshal(blockchain)
//如果error不为空
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 = blc.NewBlockchain()
run()
}
3.测试阶段
编译运行Server.go启动服务
启动之后访问: http://localhost:8080/blockchain/get会看到一个创世区块的结构
添加数据到区块链: http://localhost:8080/blockchain/write?data=send 1 eth to Alice,会产生一个新的区块