前言
源于我对区块链挖矿的好奇,最近沉迷于学习GO语言,并用它简单实现了pow挖矿的原理。
代码实现过程
定义块信息结构体:
type Block struct {
//当前区块的Hash值.
HashCode string
//当前时间戳.
TimeStamp string
//当前长度.
Index int
//网络难度系数,若前导0个数符合难度系数,则挖矿成功,根据挖矿人数不断变化.
Diff int
//下一个区块的Hash值
PreHashCode string
//随机数
Nonce int
//交易信息.
Data string
}
创建创世块
func initFirstBlock() *Block{
var firstBlcok = new(Block)
firstBlcok.TimeStamp = string(time.Now().UnixNano())
firstBlcok.Diff = 3
firstBlcok.Nonce = 1
firstBlcok.PreHashCode = "0"
firstBlcok.Data = "创世块"
firstBlcok.Index = 1
for ; ; {
hashCode := generateHashCode(*firstBlcok)
fmt.Println(hashCode)
if strings.HasPrefix(hashCode, strings.Repeat("0", firstBlcok.Diff)) {
firstBlcok.HashCode = hashCode
break
}else {
firstBlcok.Nonce++
}
}
fmt.Println("创世模块初始化完毕")
return firstBlcok
}
生成hash值的工具
用于生成Block块中的HashCode
//计算hash值.
func generateHashCode(block Block) string {
//生成规则.
record := strconv.Itoa(block.Index) + block.TimeStamp +
strconv.Itoa(block.Nonce) + strconv.Itoa(block.Diff) + block.PreHashCode
hash := sha256.New()
hash.Write([]byte(record))
sum := hash.Sum(nil)
hashCode := hex.EncodeToString(sum)
return hashCode
}
有了块以后,开始创建链
type Node struct {
block Block
nextBlock Block
index int
}
func initFirstChain(block *Block) *Node {
node := new(Node)
node.index = 1
return node
}
func createNextNode(block Block,node *Node) *Node {
nextNode := new(Node)
nextNode.index = node.index + 1
node.nextBlock = block
return nextNode
}
POW挖矿
func calNextBlock(diff int, block *Block) Block {
nextBlock := new(Block)
nextBlock.Index = block.Index + 1
nextBlock.TimeStamp = string(time.Now().UnixNano())
marshal, _ := json.Marshal(block)
nextBlock.Data = string(marshal)
nextBlock.Diff = diff
nextBlock.PreHashCode = block.HashCode
for ; ; {
hashCode := generateHashCode(*nextBlock)
fmt.Println(hashCode)
if strings.HasPrefix(hashCode, strings.Repeat("0", nextBlock.Diff)) {
nextBlock.HashCode = hashCode
break
}else {
nextBlock.Nonce++
}
}
fmt.Println("挖矿成功!!!")
return *nextBlock
}
主函数
func main() {
now := time.Now()
//初始化创世模块
firstBlock := initFirstBlock()
//初始化链表
chain := initFirstChain(firstBlock)
//开始挖坑
block := calNextBlock(6, firstBlock)
node := createNextNode(block, chain)
fmt.Println(node)
elapsed := time.Since(now)
fmt.Println("用时:", elapsed)
}
测试结果
总结
diff的值决定了挖矿的难度系数,系统会根据diff的值,不断地进行hash碰撞,直到碰撞出符合条件的hash值则表明挖矿成功,然后把这一个块上传更新到链上。