基本原理这里就不写了,只写一个简单demo的实现
首先得有一个区块用来存储区块头和区块体
type Block struct { Version int64 PreBlockHash []byte Hash []byte //区块体内是不存储HASH值的,这是网络中某个节点在计算时存储在息本地的,这里是为了方便实现最终的功能做的 TimeStamp int64 TargetBits int64 //难度值 Nonce int64 MerkelRoot []byte Data []byte //区块体信息 }
还得有一个方法用于实现区块体
func NewBlock(data string, prevBlockHash []byte) *Block { //initial block data block := &Block{ Version:1, PreBlockHash:prevBlockHash, //Hash:[] TimeStamp:time.Now().Unix(), TargetBits:10, Nonce:5, MerkelRoot:[]byte{}, Data:[]byte(data), } block.SetHash() //get block hash return block }
那区块体的hash值计算就得使用另外一个方法来实现
func (block *Block)SetHash() { tmp := [][]byte{ IntToByte(block.Version), block.PreBlockHash, IntToByte(block.TimeStamp), block.MerkelRoot, IntToByte(block.Nonce), block.Data, } data := bytes.Join(tmp, []byte{})//join接收两个参数,第一个二维数组,第二个这里设置为空的连接符 hash := sha256.Sum256(data) block.Hash = hash[:] }
区块有了,那么得一个能实现把区块连接起来的文件,blockchain.go
package main import "os" type BlockChain struct { blocks []*Block } func NewBlockChain() *BlockChain { return &BlockChain{[]*Block{NewGensisBlock()}} //添加了创世块 } func (bc *BlockChain)AddBlock(data string) { if len(bc.blocks) <= 0{ os.Exit(1) } lastBlock := bc.blocks[len(bc.blocks)-1] //还没取呢,如果取要取前一个块的HASH值,即取当前链最后一个块的HASH值 prevBlockHash := lastBlock.Hash block := NewBlock(data, prevBlockHash)//取前一个块的hash值 bc.blocks = append(bc.blocks, block) }
上面两个文件涉及到的工具写在另外一个文件
package main import ( "bytes" "encoding/binary" "fmt" "os" ) func IntToByte(num int64) []byte { var buffer bytes.Buffer err := binary.Write(&buffer, binary.BigEndian, num)//将int类型的num使用binary的方法传递到buffer里去 CheckError(err) return buffer.Bytes() } func CheckError(err error) { if err != nil { fmt.Println("err occur: ", err) os.Exit(1) } } func NewGensisBlock() *Block { //创建创世块 return NewBlock("Gensis Block!", []byte{}) }
最后主函数的实现
package main import "fmt" func main() { bc := NewBlockChain{} bc.AddBlock("班长转给老师一枚BTC") bc.AddBlock("班长又转给老师一枚BTC") for i, block := range bc.blocks {//完成区块的遍历 fmt.Println("============= block num : ", i) fmt.Println("Version", block.Version) fmt.Printf("PreBlockHash: %x ", block.PreBlockHash) fmt.Printf("Hash: %x ", block.Hash) fmt.Printf("TimeStamp: %x ", block.TimeStamp) fmt.Printf("Nonce: %x ", block.Nonce) fmt.Printf("MerkelRoot: %x ", block.MerkelRoot) fmt.Printf("Data: %s ", block.Data) } }