區塊鍊實戰
**注意:**區塊不存儲hash值,節點接受區塊後獨立計算并存儲在本地。
Version 1
區塊相關:
1.定義一個區塊的結構Block
a.區塊頭:6個字段
b.區塊體:字元串表示data
提供一個建立區塊的方法
NewBlock(參數)
區塊鍊相關
定義一個區塊鍊結構BlockChain
Block數組
提供一個建立BlockChain()的方法
NewBlockChain()
提供一個添加區塊的方法
AddBlock(參數)
block.go檔案
package main
import (
"bytes"
"crypto/sha256"
"time"
)
/*
1.定義一個區塊的結構Block
a.區塊頭:6個字段
b.區塊體:字元串表示data
*/
//區塊
type Block struct {
Version int64 //版本
PerBlockHash []byte //前一個區塊的hash值
Hash []byte //目前區塊的hash值,是為了簡化代碼
MerKelRoot []byte //梅克爾根
TimeStamp int64 //時間抽
Bits int64 //難度值
Nonce int64 //随機值
//區塊體
Data []byte //交易資訊
}
/*
提供一個建立區塊的方法
NewBlock(參數)
*/
func NewBlock(data string ,prevBlockHash []byte) *Block {
var block Block
block = Block{
Version: 1,
PerBlockHash: prevBlockHash,
//Hash: []byte{}, //區塊不存儲hash值,節點接受區塊後獨立計算并存儲在本地。
MerKelRoot: []byte{},
TimeStamp: time.Now().Unix(),
Bits: 1,
Nonce: 1,
Data: []byte(data),
}
block.SetHash() //填充Hash
return &block
}
func (block *Block) SetHash() {
// 源碼裡面是要傳二維切片 func Join(s [][]byte, sep []byte) []byte
tmp :=[][]byte{
IntToByte(block.Version),
block.PerBlockHash,
block.MerKelRoot,
IntToByte(block.TimeStamp),
IntToByte(block.Bits),
IntToByte(block.Nonce),
}
data:=bytes.Join(tmp,[]byte{}) //之後再計算hash
hash := sha256.Sum256(data)
block.Hash = hash[:] //變切片
}
//創始塊
func NewGensisBlock() *Block{
return NewBlock("Genesis Block!",[]byte{})
}
blockChain.go檔案
package main
/*
1. 定義一個區塊鍊結構BlockChain
Block數組
*/
type BlockChain struct {
blocks []*Block
}
/*
2. 提供一個建立BlockChain()的方法
NewBlockChain()
*/
func NewBlockChain() *BlockChain {
block := NewGensisBlock()
return &BlockChain{blocks:[]*Block{block}} //建立隻有一個元素的區塊鍊,初始化
}
/*
3. 提供一個添加區塊的方法
AddBlock(參數)
*/
func (bc *BlockChain)AddBlock(data string) {
PerBlockHash := bc.blocks[len(bc.blocks)-1].Hash //這一個區塊的哈希是前一塊的哈希值
block := NewBlock(data,PerBlockHash)
bc.blocks = append(bc.blocks,block)
}
utils.go檔案
package main
import (
"bytes"
"encoding/binary"
"fmt"
"os"
)
func IntToByte(num int64) []byte {
//func Write(w io.Writer, order ByteOrder, data interface{}) error {
var buffer bytes.Buffer
err := binary.Write(&buffer, binary.BigEndian, num)
CheckErr("IntToByte",err)
return buffer.Bytes()
}
func CheckErr(position string,err error) {
if err != nil {
fmt.Println("error ,pos:",position,err)
os.Exit(1)
}
}
main.go檔案
package main
import "fmt"
func main() {
bc := NewBlockChain()
bc.AddBlock("A send B 1BTC")
bc.AddBlock("B send C 1BTC")
for _,block := range bc.blocks {
fmt.Printf("Version : %d\n",block.Version)
fmt.Printf("PerBlockHash : %x\n",block.PerBlockHash)
fmt.Printf("Hash : %x\n",block.Hash)
fmt.Printf("MerKelRoot : %x\n",block.MerKelRoot)
fmt.Printf("TimeStamp : %d\n",block.TimeStamp)
fmt.Printf("Bits : %d\n",block.Bits)
fmt.Printf("Nonce : %d\n",block.Nonce)
fmt.Printf("Data : %s\n",block.Data)
}
}
執行結果