基于Web服务器的Pow案例
1.案例目标
- 程序运行,开放9000端口
- 可以通过POST方式访问,添加新的区块
- 也可以通过GET方式访问,查看区块链的信息
2.安装依赖软件 - go get github.com/davecgh/go-spew/spew
- 在控制台格式化输出结果
- go get github.com/gorilla/mux
- 编写Web程序的软件包
- go get github.com/joho/godotenv
- 用于读取GOPATH/src下的.env文件
代码实现
创建main.go
package main
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"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)
}