区块链学习Day07(Pow案例实现中)

Pow案例实现上回顾看

基于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))
}

猜你喜欢

转载自blog.csdn.net/weixin_44774466/article/details/135185720