简单区块链的实现(带POW挖矿系统)
蓝天天使2017
发表于 2022-12-7 11:38:58
137
0
0
代码分析) F3 h" E7 A' g0 i3 M6 t) A2 ?
三大模块+ a% O( K9 G0 h3 U) q, E
代码还是比较简单清晰的,主要有三个模块,Block模块、BlockChain模块、POW模块即挖矿模块。6 r, [! x# p) M7 I4 z7 i
运行流程, z2 I: L3 z. O8 C
首先从定义一个区块开始,一个区块中包含的信息有区块信息,时间戳,前区块哈希值,现区块哈希值,经过挖矿后得到的哈希碰撞值等等。
接着我们开启一个切片用来存放一个个区块,但是第一个区块是比较特殊的,我们称之为创世区块,在真实的比特币中,第一个区块是由创始人中本聪挖矿所得,没有前哈希值,所以这里我们直接将第一个创世区块创建添加到区块切片中。
然后给到一个添加区块的方法,用户添加区块信息后,经过POW挖矿系统才能成功添加到区块链上。" z1 T: b) @5 p! Y1 ~( ^ c# H
有了大概的运行流程接下来再来看代码就会轻松很多了。
package main! ?! b. P" |# K% `+ Y1 D$ N& N0 R
import (0 X b% E' W0 A6 G
"math/big"
"bytes"
"encoding/binary"
"crypto/sha256"1 X. ?2 |$ O4 f1 ?- |: [
"fmt"
"time" b- \' Y* D0 u L
)4 d: S4 O* Y( K) t+ T
//Block模块/ E. ~( x d) b7 x5 E1 z' }
type Block struct {. [2 F: I$ }' D2 E% L. u
Version uint64 //版本号
MerkelRoot []byte //这是一个默克尔数,这里先默认为空
TimeStamp string //时间戳
Difficulty uint64 //难度值9 G' Z( g0 b9 }% ~6 d- K
Nonce uint64 //挖矿所找到的随机数
PrevBlockHash []byte//前区块哈希值, i g" X9 X- [% J# O* z0 U, k4 Q8 w
Data []byte //插入的数据
Hash []byte //当前区块哈希值. M7 |6 F4 T2 L% {6 _, u
}
//给到一个创建新区块的方法
func newBlock(data,prehash []byte)*Block {; k" g$ `* ~$ C0 p4 b" A
block:=Block{- c8 z% P8 I3 e- _% w( c' ^
Version:00,0 N5 z& Y# X4 r5 c+ q+ Z8 T
MerkelRoot:[]byte{},4 a, i6 k6 A; |
TimeStamp:time.Now().Format("2006-15:04:05"),, H" y2 ?4 s/ I
Difficulty:difficulty,
Data:data,
PrevBlockHash:prehash,2 M# ^! H4 i, ~7 x! |% s
}8 p8 [& S8 c" y/ J0 X
//需要被挖矿之后才能创建区块,所以调用挖矿函数
pow:=NewPOW(&block)% A9 c# ~4 F( P8 _
nonce,hash:=pow.Mine()+ J7 M1 Y1 [9 |1 u" C1 X; X0 Q2 S
//挖矿结束,得到哈希碰撞值
block.Nonce=nonce) b2 d) x" D. E0 F
block.Hash=hash: U$ h5 M+ P# m- z
return &block: B3 _/ e9 w8 _2 o4 k& _
}+ p4 w6 e- {$ N% N5 _
//Blockchain模块% W0 n, z3 K- G7 m. H' D( \& X
const gnnesinfo="1996年9月2日,一代伟人诞生了"
//给到一个区块链结构3 b! i; }% B+ r' J# ^" P6 f
type Blockchain struct {; c' g( |" }9 y* @: r$ E
blocks []*Block
}& X, K# z5 D" J- [: z& w
//将创世区块加入区块链,并返回一条可供操作的区块链4 g2 U) t1 i- H' x& e
func NewblockChain()*Blockchain {) V4 S7 I9 k& d
var bc Blockchain
block:=newBlock([]byte(gnnesinfo),[]byte{})
bc.blocks=append(bc.blocks,block)
return &bc6 q/ K7 K6 C5 q$ ~; M: k8 g @( q
}
//给到一个增加区块的方法
func (this *Blockchain)Addblock(data []byte) {
lastblockhash:=this.blocks[len(this.blocks)-1].Hash" l% w5 k) h3 S0 H" U
block:=newBlock(data,lastblockhash)
this.blocks=append(this.blocks,block)$ X: V. m4 H/ b! E( Y/ i; g
}
//遍历,打印所有1 h; c0 m+ f" S% h7 \) b
func (this *Blockchain)PrintAll() {* q$ e! e/ u! n F
for i,v:=range this.blocks {
fmt.Printf("=========区块高度%d=========\n",i)
fmt.Printf("Version : %d\n", v.Version)- G6 U0 Q& W9 ?, T8 ~% |
fmt.Printf("PrevBlockHash : %x\n", v.PrevBlockHash)
fmt.Printf("Hash : %x\n", v.Hash)
fmt.Printf("MerkleRoot : %x\n", v.MerkelRoot)0 W: i; b4 H) k1 q. K
fmt.Printf("TimeStamp : %s\n", v.TimeStamp)
fmt.Printf("Difficuty : %d\n", v.Difficulty)$ o. v: J- G* d- M
fmt.Printf("Nonce : %d\n", v.Nonce)6 J* M) L; m6 d
fmt.Printf("Data : %s\n", v.Data)0 p0 n* s5 k4 H' C
}$ M0 p: n# Z5 n. d5 p( `
}/ i% r. d$ U% s7 [1 Q
//pow挖矿模块
const difficulty=24! g7 {) p# h9 I7 l% H. h6 X1 V- t
//POW挖矿结构需要两个参数,一个是所需挖矿的区块,另一个是挖矿成功所需目标数字
type ProofOfWork struct {
target *big.Int
block *Block( t% n6 x( w1 _0 `1 F% q% a
}
//给到一个根据难度值得到哈希碰撞目标值的函数$ ~' B. j6 ?5 N8 s: r4 x, b
func Gettargetint()*big.Int {2 Z `3 p3 A# g6 M3 k
targetint:=big.NewInt(1)
targetint.Lsh(targetint,256-difficulty)* \6 g$ d$ j& `- N8 L2 ^0 h
return targetint
}( f5 ?- e' I5 e) j- {$ F- O
//创建挖矿的方法2 }9 i2 c8 t4 m# s" B8 [
func NewPOW(block *Block)*ProofOfWork {
var this ProofOfWork, q; j, G) V1 s$ r, g9 D
this.block=block
targetint:=Gettargetint()
this.target=targetint3 S) r- J0 s+ z0 N- N, n
return &this
}
//一个用来将uint64转化为字符切片的小函数,方便接下来的转化
func uint2byte(num uint64)[]byte {3 Q" \( O2 H4 x7 z4 q
var buff bytes.Buffer
binary.Write(&buff,binary.BigEndian,&num). U! m1 ]' `1 \0 }! [# X3 s# m
return buff.Bytes()
}
//挖矿的准备工作,将其他字符组合起来之后求其哈希值
func (pow *ProofOfWork)PreparetoMine(nonce uint64)[]byte {
info:=[][]byte{
pow.block.PrevBlockHash,9 Y, i R' L- j* V6 [5 ^
pow.block.Data,- T" v/ N9 }* F: {4 A+ N( J
uint2byte(nonce),4 R9 Q) `# k" I9 z' U
uint2byte(pow.block.Version),& p- y5 v' d4 }0 E# n+ C8 }
uint2byte(pow.block.Difficulty),; W9 b, [) a2 |+ l0 w
[]byte(pow.block.TimeStamp),# R9 W/ T9 g5 ]7 }# l
pow.block.MerkelRoot,
}
allinfo:=bytes.Join(info,[]byte{})
hash:=sha256.Sum256(allinfo)
return hash[:]
}: \5 Z2 ?9 y4 a" I
//pow挖矿方法,返回两个参数,一个是碰撞成功的数字nonce,另一个是当前区块哈希值
func (pow *ProofOfWork)Mine()(uint64,[]byte) {7 a7 a" ^( Q. B3 C* x
var nonce uint648 c& {3 i0 _) W& P6 A! w) q1 F" v
//nonce从0开始穷举,直到出现哈希值小于给到的目标值# E! Y! x( D, q
var hash []byte/ Q0 e! l* f7 O3 B( W5 G
for {
hash=pow.PreparetoMine(nonce)
var hashint big.Int
hashint.SetBytes(hash)
//对比哈希值是否小于目标值,小于则成功退出
if hashint.Cmp(pow.target)==-1 {
break* \) u7 W% X+ s9 N
}7 ?$ e' y$ Y" t
//不小于则继续穷举6 l; {0 ]& v: U, m/ o
nonce++
}* j$ }. o% L; l' G
return nonce,hash
}: \7 i9 u/ k( ^6 Y7 O5 ~0 N
//调用* y; X+ j' J' `
func main() {- ]5 A% W+ Q" b# p* Y0 ^8 E$ p
bc:=NewblockChain()
bc.Addblock([]byte("welcometo"))
bc.Addblock([]byte("mycsdnblog"))6 s( W" I! u7 L* l; t2 ~) Q
bc.PrintAll()
}6 o. ]( s9 i% b. ~) H* w$ d
以上就是一个微型的区块链了,虽然看起来很简单,但是对于理解比特币、区块链还是有不少帮助的。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
猜你喜欢
成为第一个吐槽的人