简单区块链的实现(带POW挖矿系统)
蓝天天使2017
发表于 2022-12-7 11:38:58
136
0
0
代码分析9 X e6 {$ ?1 {$ r1 H; R
三大模块( u% ]. I' ?1 z2 i; Y9 ?
代码还是比较简单清晰的,主要有三个模块,Block模块、BlockChain模块、POW模块即挖矿模块。# X8 O, T5 D( O* Q( Y0 N
运行流程
首先从定义一个区块开始,一个区块中包含的信息有区块信息,时间戳,前区块哈希值,现区块哈希值,经过挖矿后得到的哈希碰撞值等等。2 B7 h; l: c7 ^+ y& Q- n& g7 H$ I s
接着我们开启一个切片用来存放一个个区块,但是第一个区块是比较特殊的,我们称之为创世区块,在真实的比特币中,第一个区块是由创始人中本聪挖矿所得,没有前哈希值,所以这里我们直接将第一个创世区块创建添加到区块切片中。
然后给到一个添加区块的方法,用户添加区块信息后,经过POW挖矿系统才能成功添加到区块链上。
有了大概的运行流程接下来再来看代码就会轻松很多了。! ]" _0 ~0 X- g2 e/ V
package main0 W; | f% k. p. Y6 t
import (
"math/big"
"bytes"3 L. a P ^' ^" [5 Y5 o& ^% b
"encoding/binary"& R* A% H- A* W% O5 ^1 G% x* R
"crypto/sha256"
"fmt"
"time": @7 G9 K" G. f% p4 r, y
)
//Block模块- `" s7 x2 M- K7 N. z
type Block struct {
Version uint64 //版本号! I7 f" z! D" s3 x/ y' d6 I& J
MerkelRoot []byte //这是一个默克尔数,这里先默认为空
TimeStamp string //时间戳
Difficulty uint64 //难度值
Nonce uint64 //挖矿所找到的随机数
PrevBlockHash []byte//前区块哈希值
Data []byte //插入的数据5 ^+ U1 X/ Z. f+ ]+ i Z! ]
Hash []byte //当前区块哈希值
}: Z7 N- A& U* T1 U1 x
//给到一个创建新区块的方法
func newBlock(data,prehash []byte)*Block {2 u* C9 P& K4 X5 o
block:=Block{
Version:00,
MerkelRoot:[]byte{},3 ]; _2 A( ~1 q4 ^
TimeStamp:time.Now().Format("2006-15:04:05"),% D0 ~1 O- o9 D3 e" @2 y2 j+ j/ ~, o
Difficulty:difficulty,& S% P5 p1 Y, A" i- A
Data:data,: i5 z% w' w0 i' u4 n9 _
PrevBlockHash:prehash,
}6 {! h' U+ g$ S6 h
//需要被挖矿之后才能创建区块,所以调用挖矿函数
pow:=NewPOW(&block)
nonce,hash:=pow.Mine()
//挖矿结束,得到哈希碰撞值5 Y0 d: V. x/ @9 o5 u: a$ U. `7 N
block.Nonce=nonce& K. ?" D! ?- U$ ^
block.Hash=hash5 O7 L" E% Y/ d4 E* P' t9 o
return &block
}
//Blockchain模块+ _9 c* }& Y0 F, K0 V
const gnnesinfo="1996年9月2日,一代伟人诞生了" 8 _! Q. {0 a$ p" k t' u! g8 R
//给到一个区块链结构
type Blockchain struct {7 f r0 Z: m9 T3 B. _/ z
blocks []*Block% e8 }- ~6 |0 h& C3 [1 `4 x0 w
}6 M$ ~1 j* { H8 O) F% G
//将创世区块加入区块链,并返回一条可供操作的区块链! n0 ^2 c, s! y; P
func NewblockChain()*Blockchain {
var bc Blockchain+ H7 N; F' P' |. w/ m3 T
block:=newBlock([]byte(gnnesinfo),[]byte{}). X0 J5 n2 I. v% g x4 h
bc.blocks=append(bc.blocks,block)4 d4 q' ~/ V4 c! l
return &bc; S. x, i2 R+ y& w* \8 L
}
//给到一个增加区块的方法; m( d3 w0 R8 M9 ^+ v- E
func (this *Blockchain)Addblock(data []byte) {/ f) x' `/ A. Z6 U
lastblockhash:=this.blocks[len(this.blocks)-1].Hash7 x) C! Z5 l3 ~: U/ X2 w+ y
block:=newBlock(data,lastblockhash)2 {* M" C& s- d1 N. ~0 ?
this.blocks=append(this.blocks,block)8 ^3 w5 q7 v# P% ?+ \' B
}# s+ U- O; c% U. J. P7 }8 R
//遍历,打印所有
func (this *Blockchain)PrintAll() {
for i,v:=range this.blocks {
fmt.Printf("=========区块高度%d=========\n",i)
fmt.Printf("Version : %d\n", v.Version)
fmt.Printf("PrevBlockHash : %x\n", v.PrevBlockHash)
fmt.Printf("Hash : %x\n", v.Hash)
fmt.Printf("MerkleRoot : %x\n", v.MerkelRoot)
fmt.Printf("TimeStamp : %s\n", v.TimeStamp)
fmt.Printf("Difficuty : %d\n", v.Difficulty)8 T& b, e& \0 e3 s+ u: o
fmt.Printf("Nonce : %d\n", v.Nonce)7 [/ [ {$ B7 R+ ~
fmt.Printf("Data : %s\n", v.Data)
}
}# Q2 [, L/ c" M; v6 x$ x9 ^* S" |: @
//pow挖矿模块
const difficulty=24, R4 l: {/ P! M# R
//POW挖矿结构需要两个参数,一个是所需挖矿的区块,另一个是挖矿成功所需目标数字1 ~! O' O' Y/ I) _6 ]7 G
type ProofOfWork struct {0 {/ v8 Y! S6 u' R2 U3 q& a; L$ S) B! ?
target *big.Int
block *Block
}
//给到一个根据难度值得到哈希碰撞目标值的函数
func Gettargetint()*big.Int {
targetint:=big.NewInt(1)
targetint.Lsh(targetint,256-difficulty)
return targetint, b6 \4 M: ^; _5 U. w8 T1 v
}* k, u1 N5 ]* x @. G H
//创建挖矿的方法
func NewPOW(block *Block)*ProofOfWork {) V, L7 ]: Y% b0 M$ l
var this ProofOfWork
this.block=block
targetint:=Gettargetint()8 s! j# S: h5 V
this.target=targetint
return &this
}, _& e' ^2 I1 h8 c, a6 r
//一个用来将uint64转化为字符切片的小函数,方便接下来的转化
func uint2byte(num uint64)[]byte {8 Y; S9 Q1 z2 S3 ^, ^, B% `
var buff bytes.Buffer8 T* M% u# z, d" M z1 r8 _
binary.Write(&buff,binary.BigEndian,&num)
return buff.Bytes()* F/ W% _, s9 A: |
}
//挖矿的准备工作,将其他字符组合起来之后求其哈希值* S! j0 v0 V7 c1 N
func (pow *ProofOfWork)PreparetoMine(nonce uint64)[]byte {
info:=[][]byte{% k ^" o/ y! V, A
pow.block.PrevBlockHash,
pow.block.Data, T. |6 W: |, X7 t6 ]1 t' u
uint2byte(nonce),9 u& Q# S9 @ T3 q5 A
uint2byte(pow.block.Version),, P9 F V% J7 r6 _$ q
uint2byte(pow.block.Difficulty),
[]byte(pow.block.TimeStamp),7 F8 E8 ?! Y7 }
pow.block.MerkelRoot,9 u. J% T6 l3 R
}
allinfo:=bytes.Join(info,[]byte{})
hash:=sha256.Sum256(allinfo)
return hash[:]
}( w2 g3 m! b8 ^ l( s* [5 ^" ~
//pow挖矿方法,返回两个参数,一个是碰撞成功的数字nonce,另一个是当前区块哈希值& r" l7 _+ z' `- ?# ]$ m
func (pow *ProofOfWork)Mine()(uint64,[]byte) {& N* Z, k, o- A4 O
var nonce uint64* M6 R# |! l2 p6 Q6 q& I5 `
//nonce从0开始穷举,直到出现哈希值小于给到的目标值 \0 x' Z: ?& v; c# Y% z. _
var hash []byte
for {
hash=pow.PreparetoMine(nonce)
var hashint big.Int; e) h$ k' i3 @
hashint.SetBytes(hash)
//对比哈希值是否小于目标值,小于则成功退出
if hashint.Cmp(pow.target)==-1 {6 ~: ~9 a; X: q1 F0 g1 O
break
}
//不小于则继续穷举( k+ ^2 ]" u5 Y' V# l3 {" I2 ^
nonce++$ t! C) J5 n+ X' S
}- N5 O% a4 K5 z/ C8 _: A
return nonce,hash
}( \- O2 w. t$ X6 e. H2 o0 G8 F
//调用$ K" X$ l. ?% N
func main() {# G% p2 h( E+ A
bc:=NewblockChain()
bc.Addblock([]byte("welcometo"))0 M& h4 _# i8 X7 b& Q3 X, I8 |
bc.Addblock([]byte("mycsdnblog"))& Y* p* |2 h! s2 n
bc.PrintAll()
}" x3 A1 a: l" L5 q
以上就是一个微型的区块链了,虽然看起来很简单,但是对于理解比特币、区块链还是有不少帮助的。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
猜你喜欢
成为第一个吐槽的人