简单区块链的实现(带POW挖矿系统)
蓝天天使2017
发表于 2022-12-7 11:38:58
240
0
0
代码分析
三大模块
代码还是比较简单清晰的,主要有三个模块,Block模块、BlockChain模块、POW模块即挖矿模块。0 _& w2 `$ A+ K2 \
运行流程
首先从定义一个区块开始,一个区块中包含的信息有区块信息,时间戳,前区块哈希值,现区块哈希值,经过挖矿后得到的哈希碰撞值等等。& r/ X( U$ S8 M {' Y
接着我们开启一个切片用来存放一个个区块,但是第一个区块是比较特殊的,我们称之为创世区块,在真实的比特币中,第一个区块是由创始人中本聪挖矿所得,没有前哈希值,所以这里我们直接将第一个创世区块创建添加到区块切片中。. p$ s3 M, y( b
然后给到一个添加区块的方法,用户添加区块信息后,经过POW挖矿系统才能成功添加到区块链上。9 A# x! i8 h3 B, ^: k5 E3 o
有了大概的运行流程接下来再来看代码就会轻松很多了。
package main
import (( K2 E b7 r& e* t9 I- H
"math/big"" O' D F' h! k2 Z- }0 R
"bytes", e( T$ F; } l: T, e- j3 L$ ?/ f
"encoding/binary"
"crypto/sha256"9 l% E" b0 m2 D$ ^2 |# K; r
"fmt"
"time"
)2 B+ R' I+ F; I
//Block模块
type Block struct {
Version uint64 //版本号
MerkelRoot []byte //这是一个默克尔数,这里先默认为空( [+ [8 {4 M# d* K! A3 {
TimeStamp string //时间戳
Difficulty uint64 //难度值
Nonce uint64 //挖矿所找到的随机数
PrevBlockHash []byte//前区块哈希值, y. u! C+ g2 p* o
Data []byte //插入的数据
Hash []byte //当前区块哈希值
}
//给到一个创建新区块的方法( x! [/ ~4 n- T/ a% r4 j
func newBlock(data,prehash []byte)*Block {0 b9 U, X2 ~9 ]7 T" C+ V- C
block:=Block{
Version:00,$ L4 r# V6 N4 d! x# Z- f
MerkelRoot:[]byte{},- y" Y z0 B6 |) b/ ?" j, Y! b. }/ ?, M
TimeStamp:time.Now().Format("2006-15:04:05"),4 X: Y& D5 K+ ?" L: F) q
Difficulty:difficulty,
Data:data,
PrevBlockHash:prehash,
}
//需要被挖矿之后才能创建区块,所以调用挖矿函数
pow:=NewPOW(&block)* c v5 n2 I: c/ s
nonce,hash:=pow.Mine()
//挖矿结束,得到哈希碰撞值 X& a0 Q9 g, J1 E* z/ s
block.Nonce=nonce0 @5 N* h) `4 D3 i# ~7 G
block.Hash=hash9 H( Z4 L( l& ^' _* r4 l
return &block" C% C" d' d% W7 g
}
//Blockchain模块' y j) k, P1 m( g3 R/ ^9 ]
const gnnesinfo="1996年9月2日,一代伟人诞生了" 7 _( P- X: t, u7 F6 `
//给到一个区块链结构' P! K4 p9 D7 j B1 L. s
type Blockchain struct {
blocks []*Block
}
//将创世区块加入区块链,并返回一条可供操作的区块链
func NewblockChain()*Blockchain {
var bc Blockchain) q% T2 N( k6 j4 T9 G
block:=newBlock([]byte(gnnesinfo),[]byte{})% {' {9 Z' j6 O, I, ^ n
bc.blocks=append(bc.blocks,block)8 e4 V# ~) f" e3 e( S4 R# j
return &bc* L+ u1 |! w$ w* {3 q s4 o, D4 H
}; w! v4 t/ g2 n7 E" X7 B2 m' |
//给到一个增加区块的方法
func (this *Blockchain)Addblock(data []byte) {
lastblockhash:=this.blocks[len(this.blocks)-1].Hash
block:=newBlock(data,lastblockhash)
this.blocks=append(this.blocks,block)
}
//遍历,打印所有
func (this *Blockchain)PrintAll() {
for i,v:=range this.blocks {. d3 H7 O6 R7 G4 I/ H
fmt.Printf("=========区块高度%d=========\n",i): j/ y4 x& [& T! N
fmt.Printf("Version : %d\n", v.Version)( K9 e8 U* i: _1 m3 M
fmt.Printf("PrevBlockHash : %x\n", v.PrevBlockHash)& E2 s! [% w9 O T/ w1 i, M& K
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)
fmt.Printf("Nonce : %d\n", v.Nonce)
fmt.Printf("Data : %s\n", v.Data)2 q1 }' q2 I9 Z5 _. ^. ]
}
}" E; E, k, b9 R: i5 J1 U
//pow挖矿模块; K) I. v1 n$ ]' i! B
const difficulty=24
//POW挖矿结构需要两个参数,一个是所需挖矿的区块,另一个是挖矿成功所需目标数字
type ProofOfWork struct {: i; t2 A2 ?" ^) q
target *big.Int+ \' n' o0 j4 X) y0 @7 w) b3 P
block *Block9 |" ~2 Y* _, h9 v/ p9 r
}! g: W* G3 J% W9 O; {) f M9 u
//给到一个根据难度值得到哈希碰撞目标值的函数
func Gettargetint()*big.Int {
targetint:=big.NewInt(1)4 T0 b9 w i% L0 e0 f% h7 N
targetint.Lsh(targetint,256-difficulty)
return targetint/ X% Z1 `( k- k1 I$ |! o" Z
}& p* P6 l9 O: z4 y! n
//创建挖矿的方法
func NewPOW(block *Block)*ProofOfWork {4 q$ ~+ t" E C. V" c/ t- K/ e
var this ProofOfWork2 W' E* H/ R" D' s/ T
this.block=block
targetint:=Gettargetint()
this.target=targetint* z ~ s7 B; C0 z
return &this0 Q- s& e( J1 G! a; G" }
}3 ~6 r; v5 o& Z5 z; ^$ |
//一个用来将uint64转化为字符切片的小函数,方便接下来的转化
func uint2byte(num uint64)[]byte {# @) c/ }+ {7 a. I* b8 G: h
var buff bytes.Buffer5 }* w' N% D, Y6 v! s" o
binary.Write(&buff,binary.BigEndian,&num)
return buff.Bytes()
}9 A. R, z& l: x2 g: F. W: E4 x
//挖矿的准备工作,将其他字符组合起来之后求其哈希值
func (pow *ProofOfWork)PreparetoMine(nonce uint64)[]byte {/ k5 P! I4 w, l7 I
info:=[][]byte{
pow.block.PrevBlockHash,
pow.block.Data,
uint2byte(nonce),, {( j5 e" \- ]! Y0 ~! F
uint2byte(pow.block.Version),. R4 K, ]0 s X3 C6 \% r/ W
uint2byte(pow.block.Difficulty),
[]byte(pow.block.TimeStamp),
pow.block.MerkelRoot,
}
allinfo:=bytes.Join(info,[]byte{})& V2 G9 W0 H% L
hash:=sha256.Sum256(allinfo)
return hash[:]1 L" w' }; T$ U, T( a/ c
}, w5 F7 X' e( v& Y2 \
//pow挖矿方法,返回两个参数,一个是碰撞成功的数字nonce,另一个是当前区块哈希值
func (pow *ProofOfWork)Mine()(uint64,[]byte) {
var nonce uint64$ U' ]/ N" D) M% D. n+ ?0 v$ ]7 A$ d
//nonce从0开始穷举,直到出现哈希值小于给到的目标值
var hash []byte' U5 f3 C; y# T7 l d, h$ d- A K
for {4 |* l* m* |8 e) h
hash=pow.PreparetoMine(nonce)
var hashint big.Int3 q% t0 w, X( z) @
hashint.SetBytes(hash)
//对比哈希值是否小于目标值,小于则成功退出* f& @/ y `# I: _: N
if hashint.Cmp(pow.target)==-1 {
break
}
//不小于则继续穷举) z# J* Q! u( W) ], G! [
nonce++
}
return nonce,hash7 r) H+ D U# e: A
}& w( A+ M* W9 ^
//调用, M3 p) z, F% P$ z* O
func main() {0 h4 U- {- _+ q3 e
bc:=NewblockChain()! ^: V7 X# o& m. ^* F* x
bc.Addblock([]byte("welcometo"))& U; d5 k4 j0 h3 ?
bc.Addblock([]byte("mycsdnblog"))( ~2 ^6 U: U8 a! H
bc.PrintAll()
}( P' k- |) ]7 ^
以上就是一个微型的区块链了,虽然看起来很简单,但是对于理解比特币、区块链还是有不少帮助的。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
猜你喜欢
成为第一个吐槽的人