简单区块链的实现(带POW挖矿系统)
蓝天天使2017
发表于 2022-12-7 11:38:58
238
0
0
代码分析; v0 y$ t7 }+ t% V9 f" T/ ~2 p5 s0 ^
三大模块6 N: q0 F' D# d" q( X
代码还是比较简单清晰的,主要有三个模块,Block模块、BlockChain模块、POW模块即挖矿模块。, ?- e4 r3 O6 ]) M! Q- o
运行流程
首先从定义一个区块开始,一个区块中包含的信息有区块信息,时间戳,前区块哈希值,现区块哈希值,经过挖矿后得到的哈希碰撞值等等。+ p6 n4 F/ n1 d3 ?8 S6 G
接着我们开启一个切片用来存放一个个区块,但是第一个区块是比较特殊的,我们称之为创世区块,在真实的比特币中,第一个区块是由创始人中本聪挖矿所得,没有前哈希值,所以这里我们直接将第一个创世区块创建添加到区块切片中。
然后给到一个添加区块的方法,用户添加区块信息后,经过POW挖矿系统才能成功添加到区块链上。$ [8 [, s, O0 ~& b
有了大概的运行流程接下来再来看代码就会轻松很多了。
package main
import (
"math/big"
"bytes"7 R& z: W9 Q- C% i' Z1 V
"encoding/binary"" d( E' t8 P3 N& \9 [% v! Y) f% O
"crypto/sha256"& P9 g0 I5 U) S8 ^+ J
"fmt"" n2 d6 g! |5 i" N8 w) f
"time"; Z" t/ U3 A) ~5 a& C0 Y, W
)
//Block模块0 V( E% {$ g6 n: N
type Block struct {
Version uint64 //版本号
MerkelRoot []byte //这是一个默克尔数,这里先默认为空2 v) d6 n- i) Z, L# ^7 ]; P
TimeStamp string //时间戳+ V. r2 H& z" o4 z$ }
Difficulty uint64 //难度值% ^9 r, x) a! R8 j% z- Y7 Y# [
Nonce uint64 //挖矿所找到的随机数* j. D: _# y4 v+ T
PrevBlockHash []byte//前区块哈希值5 M! O7 N) u" ]% ]) I
Data []byte //插入的数据
Hash []byte //当前区块哈希值
}
//给到一个创建新区块的方法
func newBlock(data,prehash []byte)*Block {5 n2 x( a3 V3 k! u) F
block:=Block{5 H& H0 k. n, g% `5 {' [
Version:00,1 E$ J2 a* o; i* A" X) K& e
MerkelRoot:[]byte{},
TimeStamp:time.Now().Format("2006-15:04:05"),1 L3 g- u% e7 w
Difficulty:difficulty,+ \# f0 z1 m' \8 s( p6 T3 r
Data:data,
PrevBlockHash:prehash,
}3 r5 B, g& q. J/ ]& a+ }4 C% r, V
//需要被挖矿之后才能创建区块,所以调用挖矿函数) v- x3 U! D! ^( z! X
pow:=NewPOW(&block)9 ]3 g A, X$ F. w' B. f, ]; ]5 o
nonce,hash:=pow.Mine()
//挖矿结束,得到哈希碰撞值
block.Nonce=nonce: s% Y, I6 T7 J' Q6 n5 F9 A- B
block.Hash=hash
return &block+ k& W6 C! V: A* R8 v. d+ ?3 Z
}
//Blockchain模块- d0 G$ F" w! X! V0 r0 T4 M+ k: z% y$ F
const gnnesinfo="1996年9月2日,一代伟人诞生了"
//给到一个区块链结构
type Blockchain struct {
blocks []*Block
}
//将创世区块加入区块链,并返回一条可供操作的区块链+ z: K& J n! @% u6 g- v; ^
func NewblockChain()*Blockchain {
var bc Blockchain! D, |5 N* a* Y% o, ?: `
block:=newBlock([]byte(gnnesinfo),[]byte{})) P$ l8 d. o3 O% v1 |9 F3 z" e& q
bc.blocks=append(bc.blocks,block). F% z$ @. W% N# u0 R
return &bc m. o. S( o6 m/ E5 l/ T
}6 H1 h/ h6 e; R& T/ ^2 A
//给到一个增加区块的方法! Y4 V0 a/ l9 U# z( i
func (this *Blockchain)Addblock(data []byte) {; k# H2 \0 o! p b7 g
lastblockhash:=this.blocks[len(this.blocks)-1].Hash( a8 l! C9 y: y4 K' [3 x
block:=newBlock(data,lastblockhash)$ y* v, F6 |0 }- b2 [/ ]
this.blocks=append(this.blocks,block)
}
//遍历,打印所有
func (this *Blockchain)PrintAll() {# e5 J6 A5 l q9 M1 W: U: B
for i,v:=range this.blocks {/ m; p0 ?. p ]. V9 `
fmt.Printf("=========区块高度%d=========\n",i)
fmt.Printf("Version : %d\n", v.Version)5 D3 e; E9 g3 B$ b2 U0 i" z
fmt.Printf("PrevBlockHash : %x\n", v.PrevBlockHash)4 E! u' ?7 o, l3 W# o9 `
fmt.Printf("Hash : %x\n", v.Hash)
fmt.Printf("MerkleRoot : %x\n", v.MerkelRoot)
fmt.Printf("TimeStamp : %s\n", v.TimeStamp)' J0 t- S, C# \0 [
fmt.Printf("Difficuty : %d\n", v.Difficulty)
fmt.Printf("Nonce : %d\n", v.Nonce)
fmt.Printf("Data : %s\n", v.Data)( n% O7 X2 [( j# j( I; {* D, W" T
}
}* v- ~) t( C- Q4 ?
//pow挖矿模块# \1 s/ ^* V. m0 h- [
const difficulty=24
//POW挖矿结构需要两个参数,一个是所需挖矿的区块,另一个是挖矿成功所需目标数字8 w8 w2 q- U/ ?# m
type ProofOfWork struct {
target *big.Int
block *Block+ O! K. w. B# v3 U2 g
}
//给到一个根据难度值得到哈希碰撞目标值的函数
func Gettargetint()*big.Int { R4 l) x l2 \( b- |* n* p
targetint:=big.NewInt(1)
targetint.Lsh(targetint,256-difficulty)# n, a0 i9 b* Z( y: m/ S
return targetint/ j: `5 W4 V. t. z" O
}9 ~9 K3 T, T0 A" R
//创建挖矿的方法; S0 U" r6 ~% j2 U; `1 x
func NewPOW(block *Block)*ProofOfWork {! H# G) v3 Y) [9 T& j P; v
var this ProofOfWork5 a* k4 M' d$ T$ H& \1 |
this.block=block
targetint:=Gettargetint()- W8 |3 j. {$ Z1 a! O1 h
this.target=targetint
return &this
}7 _) S/ R+ W( G7 ]8 d: R
//一个用来将uint64转化为字符切片的小函数,方便接下来的转化
func uint2byte(num uint64)[]byte {9 P/ G" A" O, ]% Y& i" T
var buff bytes.Buffer% Z1 G) N+ P4 P
binary.Write(&buff,binary.BigEndian,&num)
return buff.Bytes()' I1 g: n" o# `' e' C/ q
}0 _; D: e6 x1 U
//挖矿的准备工作,将其他字符组合起来之后求其哈希值
func (pow *ProofOfWork)PreparetoMine(nonce uint64)[]byte {
info:=[][]byte{: L0 m' f. L6 E. S+ G, A$ O8 F7 S
pow.block.PrevBlockHash,
pow.block.Data,
uint2byte(nonce),
uint2byte(pow.block.Version),
uint2byte(pow.block.Difficulty),' q! h) W' O- h2 Z( r8 U
[]byte(pow.block.TimeStamp),
pow.block.MerkelRoot,# q4 ~4 v3 j, M6 I$ e* e
}
allinfo:=bytes.Join(info,[]byte{})
hash:=sha256.Sum256(allinfo)9 a- ]8 m$ @* H$ r& p
return hash[:]
}
//pow挖矿方法,返回两个参数,一个是碰撞成功的数字nonce,另一个是当前区块哈希值3 G! [6 B0 F0 e: \! Z8 o6 ~, U& t. [
func (pow *ProofOfWork)Mine()(uint64,[]byte) {
var nonce uint64, C$ H+ ]0 I) V. [5 E, i B7 [ T
//nonce从0开始穷举,直到出现哈希值小于给到的目标值$ }& I" h2 Y0 \6 E
var hash []byte y! s* }+ [5 r+ R
for {
hash=pow.PreparetoMine(nonce)
var hashint big.Int& o0 K$ [3 e1 V5 |. T. c# Q
hashint.SetBytes(hash)
//对比哈希值是否小于目标值,小于则成功退出
if hashint.Cmp(pow.target)==-1 {
break; Z& N% s o' t, H, Z, }; j( C2 L. T0 T
}7 g" W: E0 a6 s+ ]% _$ r
//不小于则继续穷举# B# d7 V+ U. A0 s! O% J( S
nonce++
}6 Y3 C) `, ]! ~5 h, `# y
return nonce,hash9 y/ e& E! M' b& R
}
//调用
func main() {
bc:=NewblockChain()% ^5 b* a) u% P* h- r7 q
bc.Addblock([]byte("welcometo")), v0 S* P/ o( q) I5 H) I3 y
bc.Addblock([]byte("mycsdnblog"))
bc.PrintAll()% S" M0 \% ]$ p; g/ s6 y
}
以上就是一个微型的区块链了,虽然看起来很简单,但是对于理解比特币、区块链还是有不少帮助的。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
猜你喜欢
成为第一个吐槽的人