使用golang从零开始搭建基于UTXO模型的区块链(一、实现最简易的区块链)

真正理解区块链底层原理的方法就是写一个底层,UTXO模型区块链的开发难度还是比较简单的,等开发完后再去尝试一下基于account模型的。
什么是区块链以及UTXO模型和account模型等问题我就不在这里写了,网上的资料有很多,跟着写之前可以先去了解一下区块链的基础知识。

开发环境:goland+go1.20 该项目github地址:https://github.com/haojianuo/lighteningchain

创建项目

在这里插入图片描述
在这里插入图片描述

区块结构

每个区块应该包含头部(head)信息用于总结性的描述这个区块,然后在区块的数据存放区(body)中存放要保存的重要数据
首先定义区块结构体和区块链的结构体

type Block struct {
	Timestamp int64
	Hash      []byte //区块hash值就是其ID
	PrevHash  []byte
	Data      []byte
}

type BlockChain struct {
	Blocks []*Block
}

计算哈希

有了结构体后,区块的哈希计算也是必不可少的

func (b *Block) SetHash() {
	information := bytes.Join([][]byte{Int64ToByte(b.Timestamp), b.PrevHash, b.Data}, []byte{})
	hash := sha256.Sum256(information) //软件包sha256 实现 FIPS 180-4 中定义的 SHA224 和 SHA256 哈希算法。
	b.Hash = hash[:]
}

func Int64ToByte(num int64) []byte {
	var buf = make([]byte, 8)
	binary.BigEndian.PutUint64(buf, uint64(num))
	return buf
}

information变量是将区块的各项属性串联之后的字节串。bytes.Join可以将多个字节串连接,第二个参数是将字节串连接时的分隔符,这里设置为[]byte{}即为空。

创建区块和区块链

好了,区块链的准备工作完成,下面就要开始创建区块并将它们连在一起。
首先定义区块创建函数

func CreateBlock(prevhash []byte, data []byte) *Block {
	block := Block{time.Now().Unix(), []byte{}, prevhash, data}
	block.SetHash() //所有数据添加好后再计算hash
	return &block
}

可是每个区块都要链接上一个区块的hash,那第一个区块怎么办?这时就需要创世区块。

func GenesisBlock() *Block {
	genesisWords := "HelloWorld!"
	return CreateBlock([]byte{}, []byte(genesisWords))
}

把创建好的区块添加到区块链上

func (bc *BlockChain) AddBlock(data string) {
	newBlock := CreateBlock(bc.Blocks[len(bc.Blocks)-1].Hash, []byte(data))
	bc.Blocks = append(bc.Blocks, newBlock)
}

这下整个区块链就搭建好了,下面我们运行试试。对了,不要忘记初始化。

func CreateBlockChain() *BlockChain {
	myBlockchain := BlockChain{}
	myBlockchain.Blocks = append(myBlockchain.Blocks, GenesisBlock())
	return &myBlockchain
}

main函数编写运行测试区块链

接下来我们就可以运行区块链了,我们自己编写几个实例加进去然后输出看看:

func main() {
	blockchain := CreateBlockChain()
	time.Sleep(time.Second)
	blockchain.AddBlock("This is first Block after Genesis")
	time.Sleep(time.Second)
	blockchain.AddBlock("This is second!")
	time.Sleep(time.Second)
	blockchain.AddBlock("Awesome!")
	time.Sleep(time.Second)

	for num, block := range blockchain.Blocks {
		fmt.Printf("number:%d Timestamp: %d\n", num, block.Timestamp)
		fmt.Printf("number:%d hash: %x\n", num, block.Hash)
		fmt.Printf("number:%d Previous hash: %x\n", num, block.PrevHash)
		fmt.Printf("number:%d data: %s\n", num, block.Data)
	}
}

点击运行,输出如下:

number:0 Timestamp: 1677568251
number:0 hash: 5af650b22cc85f225c2c42850714be9466408025dfec7191436d7efa7a716433
number:0 Previous hash: 
number:0 data: HelloWorld!
number:1 Timestamp: 1677568252
number:1 hash: 3b2eafc41f8c0bd319fd2e7fd44ff2d15215ab931e6a599dc83b60f055653cb8
number:1 Previous hash: 5af650b22cc85f225c2c42850714be9466408025dfec7191436d7efa7a716433
number:1 data: This is first Block after Genesis
number:2 Timestamp: 1677568253
number:2 hash: 1be2cf3334f59a54a33e9c28957ecb836f17d731f6731bc7540066f99c2338c7
number:2 Previous hash: 3b2eafc41f8c0bd319fd2e7fd44ff2d15215ab931e6a599dc83b60f055653cb8
number:2 data: This is second!
number:3 Timestamp: 1677568254
number:3 hash: 460d954e05c98774b58426372f61997bed92ce7b4e2effb749b7bc2f0c19bdf3
number:3 Previous hash: 1be2cf3334f59a54a33e9c28957ecb836f17d731f6731bc7540066f99c2338c7
number:3 data: Awesome!

Process finished with the exit code 0

一切正常!

总结

本章搭建了一个最简易的区块链,主要是加深对于区块和区块链数据结构的认识。可以看出来,此项目目前并不符合高内聚低耦合思想,因此下一章将对此进行优化,并引入POW(工作量证明)共识机制。

参考资料

Subscribe to Arno
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.