简单区块链的实现(带POW挖矿系统)
蓝天天使2017
发表于 2022-12-7 11:38:58
244
0
0
代码分析
三大模块' L5 d0 O) F, A% n
代码还是比较简单清晰的,主要有三个模块,Block模块、BlockChain模块、POW模块即挖矿模块。
运行流程! P7 G1 K, q$ z. M M' c
首先从定义一个区块开始,一个区块中包含的信息有区块信息,时间戳,前区块哈希值,现区块哈希值,经过挖矿后得到的哈希碰撞值等等。' _1 s. F8 `- X) X
接着我们开启一个切片用来存放一个个区块,但是第一个区块是比较特殊的,我们称之为创世区块,在真实的比特币中,第一个区块是由创始人中本聪挖矿所得,没有前哈希值,所以这里我们直接将第一个创世区块创建添加到区块切片中。% i! w8 p5 o; H0 v8 @
然后给到一个添加区块的方法,用户添加区块信息后,经过POW挖矿系统才能成功添加到区块链上。5 l+ W9 F5 V% P a$ K. f3 f
有了大概的运行流程接下来再来看代码就会轻松很多了。
package main* a; g5 Q \ A- T2 E" H7 l& B8 [, U
import (( I1 W) Z, J6 n8 b' ` [
"math/big"
"bytes"; h! M/ }- ?( e$ w( t
"encoding/binary"
"crypto/sha256"6 [4 M! `, z, ?# x
"fmt"
"time"
)) p9 Y( f7 A3 P; o& s& D
//Block模块. N" n- r+ S6 N. E J6 G
type Block struct {
Version uint64 //版本号) w5 y* G# T. A! D- _$ a
MerkelRoot []byte //这是一个默克尔数,这里先默认为空
TimeStamp string //时间戳9 i7 R1 ]( Q+ b+ r
Difficulty uint64 //难度值9 I% A+ F* o3 t! q
Nonce uint64 //挖矿所找到的随机数
PrevBlockHash []byte//前区块哈希值
Data []byte //插入的数据; d9 s6 |; i4 P1 h D& A
Hash []byte //当前区块哈希值
}
//给到一个创建新区块的方法
func newBlock(data,prehash []byte)*Block {% ~, ^% \/ v* I
block:=Block{
Version:00,8 O1 B( o4 x; O& _$ C& z/ s; m
MerkelRoot:[]byte{},! ]5 \) G: t" U& D* z+ V
TimeStamp:time.Now().Format("2006-15:04:05"),+ _- h1 v$ t: u! h: s( J
Difficulty:difficulty, P" b3 U8 E0 u
Data:data,
PrevBlockHash:prehash,
}0 h; w7 k9 j$ z7 A5 q6 d" {
//需要被挖矿之后才能创建区块,所以调用挖矿函数
pow:=NewPOW(&block)! o* e1 y0 }% r+ H, j" ]
nonce,hash:=pow.Mine()
//挖矿结束,得到哈希碰撞值
block.Nonce=nonce B L* M8 T$ [) \+ m
block.Hash=hash
return &block
}6 y% U8 X9 M$ z. z% o- {
//Blockchain模块
const gnnesinfo="1996年9月2日,一代伟人诞生了" " J% [! O* d, H
//给到一个区块链结构 b; M' `" b+ ?& e
type Blockchain struct {& I, ]' ^* a, E9 R* D, C
blocks []*Block) W# E a1 h* \; D% U: [
}# s9 }! I) c$ D }
//将创世区块加入区块链,并返回一条可供操作的区块链- d6 m. Q" X2 s* B; v# C
func NewblockChain()*Blockchain {
var bc Blockchain
block:=newBlock([]byte(gnnesinfo),[]byte{})5 F3 z% y, |2 k- H" l% c% _
bc.blocks=append(bc.blocks,block)
return &bc
}/ \7 t3 E% E5 S3 U% Z
//给到一个增加区块的方法$ f5 h1 m- i4 |. I" p* X) J# {# L
func (this *Blockchain)Addblock(data []byte) {
lastblockhash:=this.blocks[len(this.blocks)-1].Hash
block:=newBlock(data,lastblockhash)
this.blocks=append(this.blocks,block)
}6 Y( Z B( W# E( y `
//遍历,打印所有8 L. L+ T8 ^% H! \/ v9 \* `5 @7 W! Z
func (this *Blockchain)PrintAll() {5 Q) a0 H. ^$ v% C; l. o2 M# P5 h* O. Z
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): i9 w" e* d" `: A! h
fmt.Printf("Hash : %x\n", v.Hash)- c( G& d! h- r1 w+ U
fmt.Printf("MerkleRoot : %x\n", v.MerkelRoot)* z. o$ u- `/ g3 p+ e
fmt.Printf("TimeStamp : %s\n", v.TimeStamp)
fmt.Printf("Difficuty : %d\n", v.Difficulty)' @6 u% n+ N; ]2 u2 E$ @, `8 O j
fmt.Printf("Nonce : %d\n", v.Nonce)
fmt.Printf("Data : %s\n", v.Data)" X9 Q5 y0 L% @1 F* o9 Z
}
}
//pow挖矿模块& B8 I) d& y& t' a% D
const difficulty=24
//POW挖矿结构需要两个参数,一个是所需挖矿的区块,另一个是挖矿成功所需目标数字
type ProofOfWork struct {
target *big.Int
block *Block& |1 k8 y0 x1 B' }. d
}" |( n2 Y( C# p' Z# U* g Y
//给到一个根据难度值得到哈希碰撞目标值的函数; G8 C: ^- s+ @4 ]
func Gettargetint()*big.Int {6 T9 R" g- k( s; s6 O
targetint:=big.NewInt(1)
targetint.Lsh(targetint,256-difficulty)
return targetint
}- i" \$ k; s2 E% A. {
//创建挖矿的方法
func NewPOW(block *Block)*ProofOfWork {
var this ProofOfWork% V3 ?& `; |3 F. U' L
this.block=block. A; N/ s+ W6 n" v g
targetint:=Gettargetint()$ Q! G, b4 S b N( O
this.target=targetint
return &this5 S! D9 e9 {5 L# V& Z7 E
}* K* O0 b& T6 r! E! h# H9 z
//一个用来将uint64转化为字符切片的小函数,方便接下来的转化7 e3 b% k: U/ e+ B- L0 Z* l' {
func uint2byte(num uint64)[]byte {% H5 L% \( X. k0 C( V" e! h3 `
var buff bytes.Buffer5 t* @/ a+ s2 H+ Z# t9 {& V
binary.Write(&buff,binary.BigEndian,&num)1 f5 k6 M7 c4 b9 x% `
return buff.Bytes()
}" `$ F& i2 K4 G8 }& Z: [8 y
//挖矿的准备工作,将其他字符组合起来之后求其哈希值* f3 H9 \ X$ l# n7 T5 C& t0 `: E
func (pow *ProofOfWork)PreparetoMine(nonce uint64)[]byte {
info:=[][]byte{
pow.block.PrevBlockHash,
pow.block.Data,+ G2 a; Q3 a; X& Y
uint2byte(nonce),
uint2byte(pow.block.Version),3 A+ b/ ?1 F* M
uint2byte(pow.block.Difficulty),
[]byte(pow.block.TimeStamp),
pow.block.MerkelRoot,
}
allinfo:=bytes.Join(info,[]byte{}); }+ f( @$ L0 C+ U
hash:=sha256.Sum256(allinfo)
return hash[:]
}7 ^3 W& Q; I7 R- _- o# m) A8 N
//pow挖矿方法,返回两个参数,一个是碰撞成功的数字nonce,另一个是当前区块哈希值4 M h% i6 r" y6 ~: Y
func (pow *ProofOfWork)Mine()(uint64,[]byte) {& O1 k: u: {* ]0 E$ |) ]
var nonce uint64
//nonce从0开始穷举,直到出现哈希值小于给到的目标值% U$ U& m3 A2 U$ L; F, o0 q) u y
var hash []byte( @8 v# A- e! i( B- G6 h
for {
hash=pow.PreparetoMine(nonce)
var hashint big.Int7 A: [$ s* o" ]& ?5 @+ J2 @ {
hashint.SetBytes(hash)5 o9 y, t" A' O
//对比哈希值是否小于目标值,小于则成功退出
if hashint.Cmp(pow.target)==-1 {
break
}
//不小于则继续穷举* A) e8 r" U7 r
nonce+++ i- K4 K- U. a" x( m
}
return nonce,hash
}( `7 W& I6 p# n& F5 }5 S
//调用
func main() { W& I, Y) F. ^) P8 E5 B
bc:=NewblockChain()
bc.Addblock([]byte("welcometo"))
bc.Addblock([]byte("mycsdnblog"))0 T; @ V2 l n/ V$ }
bc.PrintAll()6 u& V! d; M8 y x# S/ b
}
以上就是一个微型的区块链了,虽然看起来很简单,但是对于理解比特币、区块链还是有不少帮助的。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
猜你喜欢
成为第一个吐槽的人