/SimpleBlockChain

a simplized blockchain demo

Primary LanguageGo

SimpleBlockChain

a simplized blockchain demo

v1版本思路:

1. 区块相关

  • 定义一个区块的结构Block

    a. 区块头:6个字段

    b. 区块体:字符串表示data

  • 提供一个创建区块的方法 NewBlock(参数)

2. 区块链相关

  • 定义一个区块链结构BlockChain Block数组
  • 提供一个创建BlockChain的方法 NewBlockChain()
  • 提供一个添加区块的方法 AddBlock(参数)

一、定义Block结构

创建文件block.go,添加如下代码:

type Block struct {
    //区块头:
    //比特币网络的版本号
    Version uint64

    //当前区块的哈希,注意,这是为了方便写代码而加入的。比特币不在区块中存储当前区块的哈希值
    Hash []byte

    //前区块的哈希值,用于连接链条
    PrevBlockHash []byte
    //梅克尔根,用于快速校验区块,校验区块的完整性。
    MerkleRoot []byte
    //时间戳,表示区块创建的时间
    TimeStamp uint64
    //难度值,调整挖矿难度
    Difficuty uint64
    //随机值,挖矿需要求的数字
    Nonce uint64

    //区块体:
    //区块数据
    Data []byte
}

二、创建Block方法

继续在block.go中添加代码:

func NewBlock(data string, prevHash []byte) Block {
    var block Block
    block = Block{
        Version:       0,
        PrevBlockHash: prevHash,
        Hash:          []byte{},
        MerkleRoot:    []byte{},
        TimeStamp:     uint64(time.Now().Unix()),
        Difficuty:     10,//随便写,目前不用
        Nonce:         10,//随便写,目前不用
        Data:          []byte(data)}

    return block
}

注,此时hash值先填写空的,后面会处理。

三、定义区BlockChain结构

创建blockchain.go文件,添加如下代码:

//- 定义一个区块链结构BlockChain
//Block数组

type BlockChain struct {
    blocks []*Block
}

四、创建BlockChain方法

继续在blockchain.go中添加代码:

//- 提供一个创建BlockChain的方法
func NewBlockChain() *BlockChain {

    //创世块产生
    block := NewBlock("Genesis Block!", []byte{})

    //添加到区块链数组
    return &BlockChain{blocks:[]*Block{&block}}
}

五、添加区块

继续在blockchain.go中添加代码:

//- 提供一个添加区块的方法
//AddBlock(参数)

func (bc *BlockChain)AddBlock(data string)  {

    //获取最后一个区块
    lastBlock := bc.blocks[len(bc.blocks) -1]
    //获取最后一个区块的哈希,作为最新(当前)区块的前哈希
    prevHash := lastBlock.Hash

    block := NewBlock(data, prevHash)
    bc.blocks = append(bc.blocks, &block)
}

六、创建main函数

创建main.go,添加如下代码:

import (
    "fmt"
)

func main() {

    bc := NewBlockChain()
    bc.AddBlock("HelloWorld!")
    bc.AddBlock("Hello Itcast!")
    //block的数组
    for index, block := range bc.blocks {
        fmt.Println(" ============== current block index :", index)
        fmt.Printf("Version : %d\n", block.Version)
        fmt.Printf("PrevBlockHash : %x\n", block.PrevBlockHash)
        fmt.Printf("Hash : %x\n", block.Hash)
        fmt.Printf("MerkleRoot : %x\n", block.MerkleRoot)
        fmt.Printf("TimeStamp : %d\n", block.TimeStamp)
        fmt.Printf("Difficuty : %d\n", block.Difficuty)
        fmt.Printf("Nonce : %d\n", block.Nonce)
        fmt.Printf("Data : %s\n", block.Data)
    }
}

七、第一次测试

1. 编译

go build -o block *.go

2.执行

./block

3.效果

==可以看到目前三个区块都已经打印出来了,但是没有哈希值,这几个区块相对独立,所以接下来要实现哈希值的计算,将几个区块链接起来。==

八、计算Block哈希值

1.编写计算哈希的函数

回到block.go文件,加入如下代码,求区块哈希,==由于没有进行挖矿,所以哈希值不是N个0前导的,仅仅是哈希值而已,挖矿在后续课程中介绍==。

func (block *Block) setHash() {
    //把block的数据进行拼接,然后再做哈希运算!
    //strings.Join([]string, string)
    //["hello", "world", "itcast"], "=="   ==>hello=world=itcast
    //["hello", "world", "itcast"], ""   ==>  helloworlditcast

    tmp := [][]byte{
        uintToByte(block.Version),
        block.PrevBlockHash,
        //block.Hash, hash目前是空的,不需要填写
        block.MerkleRoot,
        uintToByte(block.TimeStamp),
        uintToByte(block.Difficuty),
        uintToByte(block.Nonce),
        block.Data}

    data := bytes.Join(tmp, []byte{})

    //[ []byte1, []byte2, []byte3 ] , []byte4    ==>  byte1 byte4 byte2 byte4 byte3 byte4
    //[ []byte1, []byte2, []byte3 ] , []byte4    ==>  byte1 byte2 byte3


    hash := sha256.Sum256(data /*[]byte*/)
    block.Hash = hash[:]
}

2.调用setHash函数

在NewBlock函数中添加如下代码

block.setHash()

具体位置如下:

image-20181009191029479

这样就实现了最基本的区块哈希计算。

3.辅助函数

在setHash中涉及到类型转换函数uintToByte,用于将unit64转换成[]byte字节流,请添加值block.go中,定义如下:

func uintToByte(num uint64) []byte {
    var buffer  bytes.Buffer

    err := binary.Write(&buffer, binary.BigEndian, num)
    if err != nil {
        fmt.Println("err happend!")
        os.Exit(1)
    }

    return buffer.Bytes()
}

九、第二次测试

重新编译,执行(参考步骤七),结果如下

 ============== current block index : 0
Version : 0
PrevBlockHash : 
Hash : 2c9b54532e99264119a6b50ecbb7ad0d8cb0450c31ca5ec6d59478e4d783f59d
MerkleRoot : 
TimeStamp : 1536280290
Difficuty : 10
Nonce : 10
Data : Genesis Block!
 ============== current block index : 1
Version : 0
PrevBlockHash : 2c9b54532e99264119a6b50ecbb7ad0d8cb0450c31ca5ec6d59478e4d783f59d
Hash : ecd0c5a9f16652affc32fb8fa1bcc210c7272e8558928b90bb860a2f28084fa5
MerkleRoot : 
TimeStamp : 1536280290
Difficuty : 10
Nonce : 10
Data : HelloWorld!
 ============== current block index : 2
Version : 0
PrevBlockHash : ecd0c5a9f16652affc32fb8fa1bcc210c7272e8558928b90bb860a2f28084fa5
Hash : d7dc63985c34ae4306c44a3c9e5cf3e2cc561d22c1207b2d59ab98f6897c2a90
MerkleRoot : 
TimeStamp : 1536280290
Difficuty : 10
Nonce : 10
Data : Hello Itcast!

v1完,别走开,后面更精彩!

十、下集预告

挖矿