# git代码管理
git clone https://gitee.com/bwcs/beijing_go_term2.git

会下载一个文件夹,名字:`beijing_go_term2`

进入到beijing_go_term2文件夹
执行git fetch origin v1:v1 拿到远程的v1并在本地创建一个v1
切换到v1分支:git checkout v1

git branch 查看当前分支

当远程有提交需要更新本地仓库时,执行:git pull,提示如下:
git branch –set-upstream-to=origin/ v1

执行:把本地的v1与远程的vi关联起来
git branch –set-upstream-to=origin/v1 v1

再次执行:git pull

定义,创建,打印区块

package main

import "fmt"

const genesisInfo = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"

type Block struct {
	PrevBlockHash []byte //前区块哈希
	Hash          []byte //当前区块哈希
	Data          []byte //数据,目前使用字节流,v4开始使用交易代替
}

//创建区块,对Block的每一个字段填充数据即可
func NewBlock(data string, prevBlockHash []byte) *Block {
	block := Block{
		PrevBlockHash: prevBlockHash,
		Hash:          []byte{}, //先填充为空,后续会填充数据
		Data:          []byte(data),
	}

	return &block
}

func main() {
	fmt.Printf("helloworld\n")

	block := NewBlock(genesisInfo, []byte{0x0000000000000000})

	fmt.Printf("PrevBlockHash : %x\n", block.PrevBlockHash)
	fmt.Printf("Hash : %x\n", block.Hash)
	fmt.Printf("Data : %s\n", block.Data)
}

实现setHash函数

//为了生成区块哈希,我们实现一个简单的函数,来计算哈希值,没有随机值,没有难度值
func (block *Block) SetHash() {
	var data []byte
	data = append(data, block.PrevBlockHash...)
	data = append(data, block.Data...)

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

在NewBlock中调用

func NewBlock(data string, prevBlockHash []byte) *Block {
	block := Block{
		PrevBlockHash: prevBlockHash,
		Hash:          []byte{}, //先填充为空,后续会填充数据
		Data:          []byte(data),
	}

	block.SetHash()  //<<<<-----看这里

	return &block
}

区块链定义及遍历打印

//创建区块链,使用Block数组模拟
type BlockChain struct {
	Blocks []*Block
}

//实现创建区块链的方法
func NewBlockChain() *BlockChain {
	//在创建的时候添加一个区块:创世块
	genesisBlock := NewBlock(genesisInfo, []byte{0x0000000000000000})

	bc := BlockChain{Blocks: []*Block{genesisBlock}}
	return &bc
}

func main() {
	fmt.Printf("helloworld\n")

	//block := NewBlock(genesisInfo, []byte{0x0000000000000000})
	bc := NewBlockChain()

	for _, block := range bc.Blocks {
		fmt.Printf("PrevBlockHash : %x\n", block.PrevBlockHash)
		fmt.Printf("Hash : %x\n", block.Hash)
		fmt.Printf("Data : %s\n", block.Data)
	}
}

添加区块

func (bc *BlockChain) AddBlock(data string) {
	//1. 创建一个区块

	//bc.Blocks的最后一个区块的Hash值就是当前新区块的PrevBlockHash
	lastBlock := bc.Blocks[len(bc.Blocks)-1]
	prevHash := lastBlock.Hash

	block := NewBlock(data, prevHash)

	//2. 添加到bc.Blocks数组中
	bc.Blocks = append(bc.Blocks, block)
}

代码重构
添加block.go
添加blockchain.go

更新补充区块字段

type Block struct {
	Version uint64 //区块版本号

	PrevBlockHash []byte //前区块哈希

	MerKleRoot []byte //先填写为空,后续v4的时候使用

	TimeStamp uint64 //从1970.1.1至今的秒数

	Difficulity uint64 //挖矿的难度值, v2时使用

	Nonce uint64 //随机数,挖矿找的就是它!

	Data          []byte //数据,目前使用字节流,v4开始使用交易代替

	Hash          []byte //当前区块哈希, 区块中本不存在的字段,为了方便我们添加进来
}

更新NewBlock函数

//创建区块,对Block的每一个字段填充数据即可
func NewBlock(data string, prevBlockHash []byte) *Block {
	block := Block{
		Version: 00,

		PrevBlockHash: prevBlockHash,

		MerKleRoot: []byte{},

		TimeStamp: uint64(time.Now().Unix()),

		Difficulity: 10, //随便写的,v2再调整

		Nonce: 10, //同Difficulty

		Data: []byte(data),

		Hash: []byte{}, //先填充为空,后续会填充数据
	}

	block.SetHash()

	return &block
}

更新SetHash函数

//为了生成区块哈希,我们实现一个简单的函数,来计算哈希值,没有随机值,没有难度值
func (block *Block) SetHash() {
	var data []byte

	//uintToByte将数字转成[]byte{}, 在utils.go实现
	data = append(data, uintToByte(block.Version)...)
	data = append(data, block.PrevBlockHash...)
	data = append(data, block.MerKleRoot...)
	data = append(data, uintToByte(block.TimeStamp)...)
	data = append(data, uintToByte(block.Difficulity)...)
	data = append(data, block.Data...)
	data = append(data, uintToByte(block.Nonce)...)

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

添加空函数uintToByte
创建新文件`utils.go`,添加内容如下:

package main

//这是一个工具函数文件

func uintToByte(num uint64) []byte {
	//TODO
	//具体实现暂略,后面再写

	return []byte{}
}

编码逻辑实现

package main

import (
	"bytes"
	"encoding/binary"
	"log"
)

//这是一个工具函数文件

func uintToByte(num uint64) []byte {
	//使用binary.Write来进行编码
	var buffer bytes.Buffer

	//编码要进行错误检查,一定要做
	err := binary.Write(&buffer, binary.BigEndian, num)

	if err != nil {
		log.Panic(err)
	}

	return buffer.Bytes()
}

使用bytes.Join改写函数

//为了生成区块哈希,我们实现一个简单的函数,来计算哈希值,没有随机值,没有难度值
func (block *Block) SetHash() {
	//var data []byte
	//
	////uintToByte将数字转成[]byte{}, 在utils.go实现
	//data = append(data, uintToByte(block.Version)...)
	//data = append(data, block.PrevBlockHash...)
	//data = append(data, block.MerKleRoot...)
	//data = append(data, uintToByte(block.TimeStamp)...)
	//data = append(data, uintToByte(block.Difficulity)...)
	//data = append(data, block.Data...)
	//data = append(data, uintToByte(block.Nonce)...)

	tmp := [][]byte{
		uintToByte(block.Version),
		block.PrevBlockHash,
		block.MerKleRoot,
		uintToByte(block.TimeStamp),
		uintToByte(block.Difficulity),
		block.Data,
		uintToByte(block.Nonce),
	}

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

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

demo 二维数组切片连接演示

package main

import (
	"strings"
	"fmt"
	"bytes"
)

func main() {
	strsA := []string{"hello", "world", "demo"}

	strRes := strings.Join(strsA, "=")
	fmt.Printf("strRes : %s\n", strRes)

	//func Join(s [][]byte, sep []byte) []byte {
	joinRes := bytes.Join([][]byte{[]byte("hello"), []byte("world"), []byte("demo")}, []byte{})
	fmt.Printf("joinRes: %s\n", joinRes)

}

打印block字段

	for i, block := range bc.Blocks {
		fmt.Printf("+++++++++++++++ %d ++++++++++++++\n", i)
		fmt.Printf("Version : %d\n", block.Version)
		fmt.Printf("PrevBlockHash : %x\n", block.PrevBlockHash)
		fmt.Printf("MerKleRoot : %x\n", block.MerKleRoot)

		timeFormat := time.Unix(int64(block.TimeStamp), 0).Format("2006-01-02 15:04:05")
		fmt.Printf("TimeStamp : %s\n", timeFormat)

		fmt.Printf("Difficulity : %d\n", block.Difficulity)
		fmt.Printf("Nonce : %d\n", block.Nonce)
		fmt.Printf("Hash : %x\n", block.Hash)
		fmt.Printf("Data : %s\n", block.Data)

		pow := NewProofOfWork(block)
		fmt.Printf("IsValid: %v\n", pow.IsValid())
	}