基于Web服务器的Pow案例
先装
安装依赖软件**
- go get github.com/davecgh/go-spew/spew
- 在控制台格式化输出结果
- go get github.com/gorilla/mux
- 编写Web程序的软件包
- go get github.com/joho/godotenv
- 用于读取GOPATH/src下的.env文件
如果安装不了,看下面步骤:
Go 1.13 及以上(推荐)
打开你的终端并执行
$ go env -w GO111MODULE=on
$ go env -w GOPROXY=https://goproxy.cn,direct
完成。
macOS 或 Linux
打开你的终端并执行
$ export GO111MODULE=on
$ export GOPROXY=https://goproxy.cn
或者
$ echo "export GO111MODULE=on" >> ~/.profile
$ echo "export GOPROXY=https://goproxy.cn" >> ~/.profile
$ source ~/.profile
完成。
Windows
打开你的 PowerShell 并执行
C:\> $env:GO111MODULE = "on"
C:\> $env:GOPROXY = "https://goproxy.cn"
继续在一遍当中的代码进行修改,不懂得看上一篇
func main() {
//测试 随便写
//var firstBlock Block
//firstBlock.Diff = 4
//firstBlock.Noce = 0
//firstBlock.PreHash = "0"
//firstBlock.BMP = 1
//firstBlock.Index = 0
//firstBlock.HashCode = "0"
//generateBlock(firstBlock, 1)
//默认加载.env文件,内置名叫就教.env 所以新建的叫.env
err := godotenv.Load()
if err != nil {
log.Fatal(err)
}
}
结果
新增代码
package main
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/davecgh/go-spew/spew"
"github.com/gorilla/mux"
"github.com/joho/godotenv"
"io"
"log"
"net/http"
"os"
"strconv"
"strings"
"sync"
"time"
)
// 设置难度系数,设置为4
const diffculty = 4
// 定义区块
type Block struct {
//区块高度
Index int
//时间戳
Timestamp string
//data,保存交易信息
BMP int
//当前区块的哈希
HashCode string
//上一个区块的哈希
PreHash string
//前导0 个数Diff
Diff int
//随机值
Noce int
}
// 用数组去维护区块链
var Blockchain []Block
// 声明个锁,以防止并发问题
var mutex = &sync.Mutex{
}
// 生成区块
func generateBlock(oldBlock Block, BMP int) Block {
//声明个新区块
var newBlock Block
newBlock.PreHash = oldBlock.HashCode
newBlock.Timestamp = time.Now().String()
//不能写死了
newBlock.Index = oldBlock.Index + 1
newBlock.BMP = BMP
newBlock.Diff = diffculty
//循环挖矿
for i := 0; ; i++ {
//每挖一次,给Noce加1
newBlock.Noce++
hash := calculateHash(newBlock)
fmt.Println(hash)
//判断前导0
if isHashValid(hash, newBlock.Diff) {
//一致
fmt.Println("挖矿成功")
newBlock.HashCode = hash
//将新的区块返回
return newBlock
}
}
}
// 按照规则生成一个Hash值
func calculateHash(block Block) string {
record := strconv.Itoa(block.Index) + block.Timestamp +
strconv.Itoa(block.Noce) + strconv.Itoa(block.BMP) + block.PreHash
sha := sha256.New()
sha.Write([]byte(record))
hashed := sha.Sum(nil)
return hex.EncodeToString(hashed)
}
// 判断哈希值的前导0个数和难度系数是否一直
func isHashValid(hash string, difficulty int) bool {
prefix := strings.Repeat("0", difficulty)
//判断这个哈希值是否为这个前缀
return strings.HasSuffix(hash, prefix)
}
func main() {
//测试 随便写
//var firstBlock Block
//firstBlock.Diff = 4
//firstBlock.Noce = 0
//firstBlock.PreHash = "0"
//firstBlock.BMP = 1
//firstBlock.Index = 0
//firstBlock.HashCode = "0"
//generateBlock(firstBlock, 1)
//默认加载.env文件,内置名叫就教.env 所以新建的叫.env
err := godotenv.Load()
if err != nil {
log.Fatal(err)
}
go func() {
//创世区块
genesisBlock := Block{
}
genesisBlock = Block{
Index: 0,
Timestamp: time.Now().String(),
BMP: 0,
HashCode: calculateHash(genesisBlock),
PreHash: "",
Diff: diffculty,
}
//将区块添加到区块链
mutex.Lock()
Blockchain = append(Blockchain, genesisBlock)
mutex.Unlock()
//格式化输出到控制台
spew.Dump(genesisBlock)
}()
//作为Http服务器的启动函数
log.Fatal(run())
}
// 将run作为Http启动函数
func run() error {
//声明一个回调函数,处理get还是Post
mux := makeMuxRouter()
httpAddr := os.Getenv("ADDR")
log.Println("Listening on", os.Getenv("ADDR"))
s := &http.Server{
Addr: ":" + httpAddr,
Handler: mux,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
//设置个最大相应头 1mb
MaxHeaderBytes: 1 << 20,
}
//监听服务打开
if err := s.ListenAndServe(); err != nil {
return err
}
return nil
}
// 回调函数
func makeMuxRouter() http.Handler {
muxRoter := mux.NewRouter()
//get 读,post写的处理
muxRoter.HandleFunc("/", handGetBlockchain).Methods("GET")
//写的操作post
muxRoter.HandleFunc("/", handWriteBlock).Methods("POSt")
return muxRoter
}
// 处理http的GET请求
// 查看区块链的信息
func handGetBlockchain(w http.ResponseWriter, r *http.Request) {
//转json
bytes, err := json.MarshalIndent(Blockchain, "", "\t")
if err !=nil{
//服务器的错误
http.Error(w,err.Error(),http.StatusInternalServerError)
return
}
io.WriteString(w,string(bytes))
}