基本链条的实现
1. 实现思路
- 定义区块结构
- 第一阶段:先实现基础字段:前区块哈希,哈希,数据
- 第二阶段:补充字段:Version,时间戳,难度值等
- 创建一个区块(提供一个方法)
- 定义区块链结构
- 提供一个创建区块链的方法
- 提供一个向区块链中添加区块的方法
- 打印区块链
2. 代码实现
Main.go
package main
import (
"fmt"
"time"
)
// 打印区块链
func main() {
bc := NewBlockChain()
time.Sleep(time.Second*1)
bc.AddBlock("25号btc暴涨20%")
time.Sleep(time.Second*1)
bc.AddBlock("27号btc暴涨10%")
time.Sleep(time.Second*1)
// 遍历区块数据
for i, block := range bc.Blocks {
fmt.Printf("\n++++++++++ 当前区块高度: %d ++++++++++\n", i)
fmt.Printf("Version: %d\n", block.Version)
fmt.Printf("PrevHash: %x\n", block.PrevHash)
fmt.Printf("MerkeleRoot: %x\n", block.MerkleRoot)
fmt.Printf("TimeStamp: %d\n", block.TimeStamp)
fmt.Printf("Bits: %d\n", block.Bits)
fmt.Printf("Nonce: %d\n", block.Nonce)
fmt.Printf("Hash: %x\n", block.Hash)
fmt.Printf("Data: %s\n", string(block.Data))
}
}
Block.go
package main
import (
"bytes"
"crypto/sha256"
"time"
)
// 定义区块结构
// 第一阶段:先实现基础字段:前区块哈希,哈希,数据
// 第二阶段:补充字段:Version,时间戳,难度值等
type Block struct {
// 版本号
Version uint64
// 前区块哈希
PrevHash []byte
// 交易的根哈希值
MerkleRoot []byte
// 时间戳
TimeStamp uint64
// 难度值,系统提供一个数据,用于计算出一个哈希值
Bits uint64
// 随机数,挖矿要求的数值
Nonce uint64
// 哈希,为了方便,把当前区块的哈希放入block中
Hash []byte
// 数据
Data []byte
}
// 创建一个区块(提供一个方法)
// 输入:数据,前区块的哈希值
// 输出:区块
func NewBlock(data string, prevHash []byte) *Block {
b := Block{
Version:0,
MerkleRoot:nil, // 随意写的
TimeStamp:uint64(time.Now().Unix()),
Bits:0, // 随意写的
Nonce:0, // 随意写的
PrevHash:prevHash,
Hash:nil,
Data:[]byte(data),
}
// 计算哈希值,对区块中的所有信息的拼接计算哈希
//TODO
b.setHash()
return &b
}
// 提供计算区块哈希值的方法
func (b*Block) setHash() {
// 比特币哈希算法:sha256
// data是block各个字段拼成的字节流
// 拼接三个切片,使用bytes.Join,接收一个二维的切片,使用一个一维的切片拼接
// func Join(s [][]byte, sep []byte) []byte
tmp := [][]byte {
uintToByte(b.Version),
b.PrevHash,
b.MerkleRoot,
uintToByte(b.TimeStamp),
uintToByte(b.Bits),
uintToByte(b.Nonce),
b.Hash,
b.Data,
}
// 使用join方法将二维切片转化为一维切片
data := bytes.Join(tmp, []byte{})
hash := sha256.Sum256(data)
b.Hash = hash[:]
}
Blockchain.go
package main
// 定义区块链结构(使用数组模拟区块链)
type BlockChain struct {
Blocks []*Block // 区块链
}
// 创世语
const genesisInfo = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"
// 提供一个创建区块链的方法
func NewBlockChain() *BlockChain {
// 创建BlockChain,同时添加一个创世块
genesisBlock := NewBlock(genesisInfo, nil)
bc := BlockChain{
Blocks:[]*Block{genesisBlock},
}
return &bc
}
// 提供一个向区块链中添加区块的方法
// 参数只需要数据,不需要提供前区块的哈希值,因为bc可以通过自己的下标拿到
func (bc *BlockChain) AddBlock(data string) {
// 通过下标,得到最后一个区块
lastBlock := bc.Blocks[len(bc.Blocks)-1]
// 最后一个区块哈希值是新区块的前哈希
prevHash := lastBlock.Hash
// 创建block
newBlock := NewBlock(data, prevHash)
// 添加bc中
bc.Blocks = append(bc.Blocks, newBlock)
}
Utils.go
package main
import (
"bytes"
"encoding/binary"
"fmt"
)
func uintToByte(num uint64) []byte {
//TODO
var buffer bytes.Buffer
err := binary.Write(&buffer, binary.LittleEndian, &num)
if err != nil {
fmt.Println("binary.Write error:", err)
return nil
}
return buffer.Bytes()
}
输出结果
++++++++++ 当前区块高度: 0 ++++++++++
Version: 0
PrevHash:
MerkeleRoot:
TimeStamp: 1611629077
Bits: 0
Nonce: 0
Hash: eb84dbcf34b4146ed89a9463f7e0af49ab21b6ab94e8835768fed10e658186a9
Data: The Times 03/Jan/2009 Chancellor on brink of second bailout for banks
++++++++++ 当前区块高度: 1 ++++++++++
Version: 0
PrevHash: eb84dbcf34b4146ed89a9463f7e0af49ab21b6ab94e8835768fed10e658186a9
MerkeleRoot:
TimeStamp: 1611629078
Bits: 0
Nonce: 0
Hash: 558e510a24a550b2aea9fcbb78b8c62e3a1916919508902f582b04930322e386
Data: 25号btc暴涨20%
++++++++++ 当前区块高度: 2 ++++++++++
Version: 0
PrevHash: 558e510a24a550b2aea9fcbb78b8c62e3a1916919508902f582b04930322e386
MerkeleRoot:
TimeStamp: 1611629079
Bits: 0
Nonce: 0
Hash: b4b6dd54fda7825ac45eb24a9ad59be9451f89cf8e6eecb9673b534e83a1e7b8
Data: 27号btc暴涨10%
此时生成的哈希值没有规则,需要工作量证明的添加