一个基于web服务器的PoW案例(一)

「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战」。

一个基于web服务器的PoW案例

本文收录于我的专栏:细讲区块链

本专栏会讲述区块链共识算法以及以太坊智能合约、超级账本智能合约、EOS智能合约相关知识,还会详细的介绍几个实战项目。如果有可能的话,我们还能一起来阅读以太坊的源码。有兴趣的话我们一起来学习区块链技术吧~

一、安装第三方库

go get github.com/davecgh/go-spew/spew
复制代码

这个库的功能是在命令行格式化输出内容。

go get github.com/gorilla/mux
复制代码

这个开发包是用来编写Web处理程序的。

go get github.com/joho/godotenv
复制代码

这个工具包是读取.env后缀名的文件中的数据,如果是Linux环境,.env文件放置在项目的根目录即可,如果是Windows和Mac OS,.env文件需要放在GOPATH/src目录下。

二、定义区块信息、难度系数

const difficulty = 4type Block struct {
    Index int
    Timestamp string
    BMP int
    HashCode string
    PreHash string
    Diff int
    Nonce int
}
​
var Blockchain []Block
type Message struct {
    BlockPostMessage int
}
var mutex = &sync.Mutex{}
复制代码

这里我们定义一下挖矿生成区块的难度值,然后定义区块,包含区块高度、时间戳、交易信息、当前的Hash值和上一个的Hash值,还有难度和随机值。

然后定义区块链,用区块数组。

然后我们这里要根据Get请求和Post请求来生成区块,所以定义一个消息结构体用于存储Post信息。

最后定义一个互斥锁。

三、生成区块

func generateBlock(oldBlock Block, BlockPostMessage int) Block {
    var newBlock Block
    newBlock.PreHash = oldBlock.HashCode
    
    newBlock.Index = oldBlock.Index + 1
    
    t := time.Now()
    newBlock.Timestamp = t.String()
    
    newBlock.BlockPostMessage = BlockPostMessage
    
    newBlock.Diff = difficulty
​
    for i := 0; ; i++ {
        newBlock.Nonce++
        hash := calculateHash(newBlock)
        fmt.Println(hash)
        
        if isHashValid(hash, newBlock.Diff) {
            fmt.Println("挖矿成功")
            newBlock.HashCode = hash
            return newBlock
        }
    }
}
复制代码

每次生成新的区块前,先获取先前区块的Hash值放置在这个区块的上一个区块Hash值,然后获取当前时间,通过String()方法转换成为时间戳后放入区块的Timestamp。然后将Post传递的消息放入区块,将我们固定不变的困难值放入区块。

然后循环挖矿,每次挖矿将随机数加一,然后先不管这个区块能不能成功并入区块链,得先计算它的哈希值才能知道,然后校验哈希值的前导0,如果成功就输出挖矿成功。

四、生成哈希值

func calculateHash(block Block) string {
    hashed := strconv.Itoa(block.Index) + block.Timestamp +
        strconv.Itoa(block.Nonce) + strconv.Itoa(block.BlockPostMessage) +
        block.PreHash
    sha := sha256.New()
    sha.Write([]byte(hashed))
    hash := sha.Sum(nil)
    return hex.EncodeToString(hash)
}
复制代码

很简单的逻辑,将区块的数据拼接后用sha256进行加密,得到hash值。