BlockChain (V1)

宋高扬
2023-12-01
// block.go
package main

import "time"
import "crypto/sha256"
import "bytes"

type Block struct {
	Version       int64  //版本信息
	PrevBlockHash []byte //前一个区块的hash值
	Hash          []byte //本区块的hash值,为了方便而做了一些简化,正常比特币区块不包含自己的hash值
	TimeStamp     int64  //时间戳,用于标记产生的时间
	TargetBits    int64  //难度值
	Nonce         int64  //随机值
	MerKelRoot    []byte //默克尔根

	Data []byte //区块体,简化,正常来说是一个交易
	//正常分区块头和区块体,这里方便编写,所以写在了一起
}

func NewBlock(data string, prevBlockHash []byte) *Block { //创建交易信息
	//data 是交易,prev是前一个区块的hash值
	block := &Block{ //初始化区块各个字段的数据
		Version:       1,
		PrevBlockHash: prevBlockHash,
		//Hash:
		TimeStamp:  time.Now().Unix(), //时间戳
		TargetBits: 10,                //没有涉及pow证明,后期选个合理的
		Nonce:      5,                 //工作量证明的,此处演示
		MerKelRoot: []byte{},          //根据交易计算出的
		Data:       []byte(data)}
	//现有的内容做一个hash运算
	block.SetHash() //设置各个字段的hash值
	return block
}

func (block *Block) SetHash() {
	//比特币用的是sha256算法

	tmp := [][]byte{
		//实现Int类型转换为byte类型的工具函数
		IntToByte(block.Version), //
		block.PrevBlockHash,
		//hash不用放了
		IntToByte(block.TimeStamp), //
		block.MerKelRoot,
		IntToByte(block.Nonce), //三个类型不对,把int转换成byte,提供工具包,来解决这个问题。
		block.Data}

	//join 将区块的各个字段连接成一个切片,使用[]byte{}空切片连接,目的是避免污染原区块的信息
	data := bytes.Join(tmp, []byte{}) //把所有指定的切片用分割符分割
	//对区块进行sha256算法,返回值为[32]byte数组
	hash := sha256.Sum256(data)
	block.Hash = hash[:] //由数组转化为切片
}

//创建比特币的创世块,即第一个区块,他的前一个区块的hash为空
func NewGenesisBlock() *Block {
	return NewBlock("Genesis Block!", []byte{})
}
//blockchain.go
package main

import "os"

type BlockChain struct { //构造区块链结构,使用数组来存储所有区块
	blocks []*Block
}

//创建区块链实例,并且添加第一个创世块
func NewBlockChain() *BlockChain {
	//new一个创世块
	return &BlockChain{[]*Block{NewGenesisBlock()}} //填第一个元素
} //到此,完成了区块链的构造

//添加其他的区块的操作

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

	//校验数组的元素个数,避免出现访问越界情况!!!直接操作下标有风险
	if len(bc.blocks) <= 0 {
		os.Exit(1)
	}

	//取出最后一个区块,目的是得到其hash值
	lastBlock := bc.blocks[len(bc.blocks)-1] //找到最后一个区块的下标,因为是数组存储
	prevBlockHash := lastBlock.Hash
	//构造新区块,且添加至整个数组中
	block := NewBlock(data, prevBlockHash) //交易信息和上一个区块的hash
	bc.blocks = append(bc.blocks, block)
}
//utls.go
package main

import "encoding/binary"
import "bytes"
import "fmt"
import "os"

func IntToByte(num int64) []byte {
	var buffer bytes.Buffer //用buffer转换

	err := binary.Write(&buffer, binary.BigEndian, num) //三个参数,传入的buffer,对齐方式,任何类型
	if err != nil {
		fmt.Println("IntToByte err occur:", err)
		os.Exit(1)
	}
	return buffer.Bytes()
}

/*
func CheckErr(err error){
	if err!=nil{
		fmt.Println("IntToByte err occur:", err)
		os.Exit(1)
	}
}
*/
//main.go
package main

import "fmt"

func main() {
	bc := NewBlockChain()
	bc.AddBlock("班长转给老师一枚BTC")
	bc.AddBlock("班长又转给老师一枚BTC")
	bc.AddBlock("小明转给老师一枚BTC")
	for i, block := range bc.blocks {

		fmt.Println("==========block num:", i)
		fmt.Println("Data:\t", string(block.Data))
		fmt.Println("Version:\t", block.Version)
		fmt.Printf("PrevBlockHash:\t %x\n", block.PrevBlockHash)
		fmt.Printf("Hash:\t\t %x\n", block.Hash)
		fmt.Printf("TimeStamp:\t %d\n", block.TimeStamp)
		fmt.Printf("MerKel:\t %x\n", block.MerKelRoot)
		fmt.Printf("Nonce:\t %d\n", block.Nonce)
		fmt.Println("\n\n")

	}

}

 

 类似资料: