前言
學了兩個月左右的區(qū)塊鏈理論知識,學來學去總是不深入,總是覺得迷迷糊糊,于是我打算自己造一個小型私有的區(qū)塊鏈。當然這一個項目我也是有借鑒前人視頻的,因為項目這個東西其實單靠一個人的力量根本搞不動的,只好借鑒前人的視頻來深化自己的基礎內(nèi)容,同時也增加自己的項目經(jīng)驗。
環(huán)境
編程語言:go語言
測試環(huán)境以及運行環(huán)境:windows11
理論知識
區(qū)塊鏈:存數(shù)據(jù)的塊+hash指針鏈。
hash:哈希,類似于一個數(shù)學函數(shù)f(x),其輸出空間f(x)為2^256次方,而輸入空間x是無限的。所以有一定幾率會有hash碰撞。
hash碰撞:就是兩個不同的輸入,卻有兩個相同的輸出。但是專家說這個幾率比bigbang還小,專家把它稱為collision resistance。此外專家還提出了其余兩個hash的性質(zhì):hiding , puzzle friendly。
collision resistance:耐撞,就是hash可以盡量避免碰撞的意思。
hiding:單向的,不可逆轉的,即知道x可以推f(x),但是知道f(x)不可以推x。
puzzle friendly:謎一般的存在,就是這玩意很難快速通過x找出f(x),只能一個個不同的x嘗試,所以這也成為了pow!
pow:proof of work,工作量證明,說白了:你家電腦開著挖礦計算f(x),電表轉了多少w(或者 嘗試x的次數(shù)),這就是你的工作量證明。進而v神提出了某太坊(也是區(qū)塊鏈),想要改變某特幣中pow為pos。
pos:proof of state,權益證明,說白了:有錢就有權!
UTXO:未花費的交易輸出,就是一個數(shù)據(jù)結構存放了未花費的交易,這樣就不用從當前區(qū)塊往前查找自己獲得的比特幣以及自己花費的比特幣來計算自己余額。
全節(jié)點:保存區(qū)塊鏈一切的信息
輕節(jié)點:只保留與自身相關的交易信息,等到需要驗證的時候,去全節(jié)點進行驗證交易信息是否偽造篡改。
交易信息:transaction,它是礦工將區(qū)塊鏈上相關的轉賬交易等進行打包,生成merkle tree,然后通過merkle tree獲得根值的hash值。
merkle tree:默克爾樹,哈希樹,葉節(jié)點鏈接交易信息,并且逐層取hash,直到獲得根hash,將其存儲block header(區(qū)塊頭),如下圖所示。
挖礦:用電獲得算力,用算力計算hash值,查看hash是否小于區(qū)塊鏈系統(tǒng)指定的target區(qū)間。這個hash值是block header中的信息進行concat(鏈接)的字節(jié),然后將這些字節(jié)進行計算獲得hash(當然nonce是可變的,所以可以使得每次輸出的hash不同,從而找到符合的hash值)
初步實現(xiàn)pow的框架
初步實現(xiàn):能算hash,讓其達到target區(qū)間內(nèi)的hash。
1.實現(xiàn)單個的block(區(qū)塊)
package block
import (
"bytes"
"crypto/sha256"
"strconv"
"time"
)
type Block struct {
//區(qū)塊 包含 高度 prevhash thishash merkleTree(交易數(shù)據(jù)) timestamp nonce
Height int64
PrevBlockHash []byte
Data []byte
thisBlockHash []byte
Timestamp int64
Nonce int64
}
// 創(chuàng)建新的區(qū)塊
func CreateBlock(data string, height int64, prevBlockHash []byte) *Block {
block := new(Block)
block.Height = height
block.Data = []byte(data)
block.Timestamp = time.Now().Unix()
block.PrevBlockHash = prevBlockHash
block.thisBlockHash = nil
block.Nonce = 0
//pow:proof of work,工作量的證明,返回hash和nonce
pow := NewProofOfWork(block)
//開始挖礦
hash, nonce := pow.Start()
//更新兩者
block.thisBlockHash = hash[:]
block.Nonce = nonce
return block
}
// 形成hash值
func (block *Block) SetHash() {
//高度字節(jié)化
height := Int64ToByte(block.Height)
//timeStamp := Int64ToByte(block.Timestamp)
//時間戳字節(jié)化
timeString := strconv.FormatInt(block.Timestamp, 2)
timeStamp := []byte(timeString)
//拼接所有屬性
blockBytes := bytes.Join([][]byte{height, block.PrevBlockHash, block.Data, timeStamp, block.thisBlockHash}, []byte{})
//形成hash
hash := sha256.Sum256(blockBytes)
//類型轉換
block.thisBlockHash = hash[:]
}
// 生成創(chuàng)世塊
func CreateGenesisBlock(data string) *Block {
genesisBlock := new(Block)
//創(chuàng)世區(qū)塊的長度為1,無前hash指針
genesisBlock.PrevBlockHash = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
genesisBlock.Data = []byte(data)
genesisBlock.Height = 1
genesisBlock.Timestamp = time.Now().Unix()
genesisBlock.SetHash()
return genesisBlock
}
2.實現(xiàn)一整條blockchain(區(qū)塊鏈)
package block
type BlockChain struct {
//存儲區(qū)塊
Blocks []*Block
}
// 創(chuàng)建帶有創(chuàng)世區(qū)塊的區(qū)塊鏈
func CreateBCWithGB() *BlockChain {
genesisBlock := CreateGenesisBlock("創(chuàng)世區(qū)塊")
return &BlockChain{[]*Block{genesisBlock}}
}
// 往區(qū)塊鏈添加新的區(qū)塊
func (bc *BlockChain) AppendBlock(data string, height int64, preHash []byte) {
newBC := CreateBlock(data, height, preHash)
bc.Blocks = append(bc.Blocks, newBC)
//newBC := block.CreateBlock(data, int64(len(bc.Blocks)), bc.Blocks[len(bc.Blocks)-1].thisBlockHash)
}
3.實現(xiàn)proof of work(工作量證明)文章來源:http://www.zghlxwxcb.cn/news/detail-777602.html
package block
import (
"bytes"
"crypto/sha256"
"fmt"
"math/big"
)
// 代表該目標區(qū)域的hash中前16位為0
const targetZeroBits = 30
type ProofOfWork struct {
block *Block //當前要驗證的區(qū)塊
target *big.Int //挖礦難度(目標區(qū)域)
}
// 拼接數(shù)據(jù),返回字節(jié)數(shù)組,以便形成hash
func (pow *ProofOfWork) prepData(nonce int64) []byte {
data := bytes.Join(
[][]byte{
pow.block.PrevBlockHash,
pow.block.Data,
Int64ToByte(pow.block.Timestamp),
Int64ToByte(int64(targetZeroBits)),
Int64ToByte(int64(nonce)),
Int64ToByte(int64(pow.block.Height))}, []byte{})
return data
}
// 啟動工作量證明(挖礦!)
func (pow *ProofOfWork) Start() ([]byte, int64) {
//1.block屬性拼接成字節(jié)數(shù)組
//2.生成hash
//3.判斷hash有效性
nonce := 0
var hashInt big.Int //用于存儲當前所生成的hash值
var hash [32]byte
for {
prep := pow.prepData(int64(nonce))
hash = sha256.Sum256(prep)
fmt.Println(hash)
hashInt.SetBytes(hash[:])
fmt.Println(hash)
if pow.target.Cmp(&hashInt) == 1 {
break
}
nonce = nonce + 1
}
return hash[:], int64(nonce)
}
// 判斷hash是否有效
func (pow *ProofOfWork) isValid() bool {
var hashInt big.Int
hashInt.SetBytes(pow.block.thisBlockHash)
if pow.target.Cmp(&hashInt) == -1 {
return false
}
return true
}
// 創(chuàng)建工作量證明的對象(礦工)
func NewProofOfWork(block *Block) *ProofOfWork {
pow := new(ProofOfWork)
//創(chuàng)建一個初始值為1的target
target := big.NewInt(1)
//左移256-targetZeroBits,這樣就可以得到它的目標區(qū)域target
target = target.Lsh(target, 256-targetZeroBits)
pow.target = target
pow.block = block
return pow
}
大致的流程如下:文章來源地址http://www.zghlxwxcb.cn/news/detail-777602.html
到了這里,關于從零到一用go語言造一個小型區(qū)塊鏈(一)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!