简单区块链的实现(带POW挖矿系统)
蓝天天使2017
发表于 2022-12-7 11:38:58
239
0
0
代码分析
三大模块1 |+ o8 Y x3 W F# B& x
代码还是比较简单清晰的,主要有三个模块,Block模块、BlockChain模块、POW模块即挖矿模块。6 p! @& ]$ B+ d7 _2 a- o l
运行流程
首先从定义一个区块开始,一个区块中包含的信息有区块信息,时间戳,前区块哈希值,现区块哈希值,经过挖矿后得到的哈希碰撞值等等。- ~. W( d: y8 u6 k% F: s4 o! H+ _
接着我们开启一个切片用来存放一个个区块,但是第一个区块是比较特殊的,我们称之为创世区块,在真实的比特币中,第一个区块是由创始人中本聪挖矿所得,没有前哈希值,所以这里我们直接将第一个创世区块创建添加到区块切片中。9 D; S& |$ f3 ?
然后给到一个添加区块的方法,用户添加区块信息后,经过POW挖矿系统才能成功添加到区块链上。 N% Q2 [& H( D4 @9 w4 k
有了大概的运行流程接下来再来看代码就会轻松很多了。
package main
import (; r& w0 X l4 k6 p
"math/big"' |1 S5 d- P8 y: S
"bytes"
"encoding/binary"
"crypto/sha256"
"fmt"
"time"
)
//Block模块
type Block struct {
Version uint64 //版本号
MerkelRoot []byte //这是一个默克尔数,这里先默认为空
TimeStamp string //时间戳
Difficulty uint64 //难度值" h6 b. ^% R' m3 [
Nonce uint64 //挖矿所找到的随机数 n- v" [* t" G
PrevBlockHash []byte//前区块哈希值3 e, L* |. W, ?! a9 r
Data []byte //插入的数据 X& g8 J& n0 P" S; o! H
Hash []byte //当前区块哈希值
}
//给到一个创建新区块的方法
func newBlock(data,prehash []byte)*Block {" y. R2 r5 W6 g8 U6 t6 @
block:=Block{
Version:00,4 s. }' J: B# ]# H2 p, D1 b/ [
MerkelRoot:[]byte{},) ~$ D# M5 f( L: q1 h
TimeStamp:time.Now().Format("2006-15:04:05"),
Difficulty:difficulty,
Data:data,
PrevBlockHash:prehash,
}3 {7 C. \/ t" E, n5 @8 @
//需要被挖矿之后才能创建区块,所以调用挖矿函数% F( E: P) l/ O# b" Q0 v
pow:=NewPOW(&block)
nonce,hash:=pow.Mine(), L% W* h8 G% |3 J
//挖矿结束,得到哈希碰撞值0 p3 y0 ^) v$ a
block.Nonce=nonce& J* Y6 @5 {) j3 s( U2 {
block.Hash=hash, g' O, R; D1 l
return &block' j( L* B% ?1 N$ ~8 {% u5 K
}
//Blockchain模块2 H5 ~1 R9 N I7 h2 {7 W
const gnnesinfo="1996年9月2日,一代伟人诞生了"
//给到一个区块链结构
type Blockchain struct {( I7 u; D% S/ [$ N* V
blocks []*Block4 u( F# j2 t, ?% f* A" h- U
}$ k0 R8 }* O( d! U j
//将创世区块加入区块链,并返回一条可供操作的区块链1 B" I2 T5 @9 N: {" l
func NewblockChain()*Blockchain {" g# |% Y, G5 {( U2 K
var bc Blockchain
block:=newBlock([]byte(gnnesinfo),[]byte{})% Y4 V# _2 Z' j) n2 l/ d2 e. a" {% i
bc.blocks=append(bc.blocks,block)* j. B" H3 _3 S. H9 S7 l5 y( N
return &bc) L: ?. J4 Z# L( i, d. m
}- d `8 A1 y; T( L
//给到一个增加区块的方法3 K0 C: m1 G0 V5 q! w. `" N
func (this *Blockchain)Addblock(data []byte) {0 j! w0 o' M& O3 R" p6 d# G/ q
lastblockhash:=this.blocks[len(this.blocks)-1].Hash" Z( q, _$ ?1 m$ e& @, E0 O
block:=newBlock(data,lastblockhash)
this.blocks=append(this.blocks,block)
}
//遍历,打印所有" |6 u& W+ C; A; L0 ~9 N1 d
func (this *Blockchain)PrintAll() {
for i,v:=range this.blocks {
fmt.Printf("=========区块高度%d=========\n",i)' B, ^8 ~( q1 j! D. b u
fmt.Printf("Version : %d\n", v.Version)
fmt.Printf("PrevBlockHash : %x\n", v.PrevBlockHash)9 R4 J- S( C& ~1 l( e1 n, \
fmt.Printf("Hash : %x\n", v.Hash)$ w% E% U: s. n
fmt.Printf("MerkleRoot : %x\n", v.MerkelRoot)
fmt.Printf("TimeStamp : %s\n", v.TimeStamp)
fmt.Printf("Difficuty : %d\n", v.Difficulty)
fmt.Printf("Nonce : %d\n", v.Nonce)1 V8 F0 Q, e/ V3 |
fmt.Printf("Data : %s\n", v.Data)% y' Y" a/ p% q; e4 U, \
}
}
//pow挖矿模块* o+ b, f: z% o& M
const difficulty=24; n2 T0 `0 T P# W( t+ x
//POW挖矿结构需要两个参数,一个是所需挖矿的区块,另一个是挖矿成功所需目标数字/ R" X# y$ @! o" a; r7 H
type ProofOfWork struct {
target *big.Int
block *Block
}0 `6 e. _4 R' U1 r
//给到一个根据难度值得到哈希碰撞目标值的函数
func Gettargetint()*big.Int {) u0 h6 j* P8 s8 c
targetint:=big.NewInt(1)6 g: V7 Y2 ~5 v [8 q; E
targetint.Lsh(targetint,256-difficulty)
return targetint& Y) w* g9 X' |
}
//创建挖矿的方法- i" I9 z/ o% D# _, O( o( k
func NewPOW(block *Block)*ProofOfWork {
var this ProofOfWork
this.block=block0 M1 x$ o( {: }- a+ p
targetint:=Gettargetint()9 o! ~* Y4 |9 k7 s$ h; G) J- _
this.target=targetint, P) E& Q/ ^) E6 f/ A: c
return &this q$ j- D) f, C+ V" |( }, O* \9 p
}
//一个用来将uint64转化为字符切片的小函数,方便接下来的转化
func uint2byte(num uint64)[]byte {0 y! L' c" \+ x5 I! e) H/ G
var buff bytes.Buffer4 _- C. g& m% { c* I4 B% l
binary.Write(&buff,binary.BigEndian,&num)
return buff.Bytes()
}) R, S8 n8 \8 b7 F7 ^! K
//挖矿的准备工作,将其他字符组合起来之后求其哈希值" e8 q) t9 ^8 `! ^7 B
func (pow *ProofOfWork)PreparetoMine(nonce uint64)[]byte {9 C. L9 |, O) l5 D( F( F2 o* h* B
info:=[][]byte{
pow.block.PrevBlockHash,- L+ d+ x3 [% s/ K
pow.block.Data,
uint2byte(nonce),
uint2byte(pow.block.Version),
uint2byte(pow.block.Difficulty),3 I$ A5 V. L# Z
[]byte(pow.block.TimeStamp),2 j$ ]: H7 M0 \* o
pow.block.MerkelRoot,
}! i" X) _$ `7 e8 i" n2 E' r
allinfo:=bytes.Join(info,[]byte{})% m( |; M4 M- p
hash:=sha256.Sum256(allinfo)
return hash[:], ]0 W) X& h) J7 M
}: `8 b% E1 N* Y/ b/ D
//pow挖矿方法,返回两个参数,一个是碰撞成功的数字nonce,另一个是当前区块哈希值( _! \& F4 m, R$ q; r$ `5 z$ q
func (pow *ProofOfWork)Mine()(uint64,[]byte) {8 L3 P0 a f6 O- ?7 `- j- Y
var nonce uint64
//nonce从0开始穷举,直到出现哈希值小于给到的目标值
var hash []byte$ |! s) H7 w0 d. ~! d0 T
for {
hash=pow.PreparetoMine(nonce)1 F* M- `# N& Y0 ^( |
var hashint big.Int/ b" X t+ s6 J [
hashint.SetBytes(hash)
//对比哈希值是否小于目标值,小于则成功退出
if hashint.Cmp(pow.target)==-1 {1 b& x' K7 I% Q& h* A0 H3 C
break
} n; z+ p! B: c1 d4 A# T) {
//不小于则继续穷举
nonce++
}6 Y/ R6 C; p/ S- I& o& W
return nonce,hash
}
//调用
func main() {: t: X( d* s9 f6 ?, o. l5 F
bc:=NewblockChain()4 }4 W0 q) j9 h- j) Y
bc.Addblock([]byte("welcometo"))+ c& t9 V5 E3 }4 Q6 M- S
bc.Addblock([]byte("mycsdnblog"))
bc.PrintAll()7 \5 D0 D* F# h
}
以上就是一个微型的区块链了,虽然看起来很简单,但是对于理解比特币、区块链还是有不少帮助的。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
猜你喜欢
成为第一个吐槽的人