一个基于 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 = 4
type 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 值。
评论