用go实现简单的区块链

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,会产生一个新的区块

 

你可能感兴趣的:(区块链)