Golang实现区块链(一)—简单区块链

随着比特币、以太坊等虚拟货币的越来越火,作为这些虚拟货币背后支撑的区块链技术,也被越来越多的人提及。下面我们将使用go语言对区块链进行探讨,并实现一个简易的区块链,本文暂不涉及poW、poS等共识算法。

通过本文,你可以做到:

  • 了解区块
  • Hash算法
  • 区块链的构建

设计逻辑

  • 区块设计
  • 区块哈希计算
  • 构建区块链
  • 添加区块到链中

区块

了解区块链,我们就得先了解它的块。在区块链中,块存储了一些信息,比如,区块所在的位置、区块创建的时间、区块存储的变量信息、区块的当前Hash值、以及上一个区块的Hash值等。

  • Index 区块位置索引
  • TimeStamp 时间戳
  • Data 存放的数据
  • PrevBlockHash 前一个区块Hash值
  • Hash 当前区块Hash值

区块结构代码

 type Block struct {
	Index  int64
	TimeStamp int64
	Data  []byte
	PrevBlockHash []byte
	Hash []byte
}

创建区块

下面我们来创建新的区块,即构建Block新对象。

func  NewBlock(index int64,data ,prevBlockHash []byte) *Block  {
	block :=&Block{index,time.Now().Unix(),data,prevBlockHash,[]byte{}}
	block.setHash() //设置当前区块Hash
	return  block
}

设置哈希函数

区块链使用的是Hash验证,那为什么使用Hash计算呢?

  1. 计算Hash非常困难,这样可以增加创建新块的难度。
  2. 只要区块的信息有任意一点变化,Hash值也会随着变化,下一个块Hash验证就通过不了,这就保证的区块的安全性。
    3.每个块上的信息,都存储在当前块的Hash上,这就节省了空间。

下面我们实现它,首先把区块中的Index 、TimeStamp处理成字符串,然后和PrevBlockHash 拼接到一起,通过SHA-256构计算它们的Hash值,并存储在当前区块Hash属性中。

func (b *Block)setHash()  {
	timestamp :=[]byte(strconv.FormatInt(b.TimeStamp,10))
	index := []byte(strconv.FormatInt(b.Index,10))
	headers :=bytes.Join([][]byte{timestamp,index,b.PrevBlockHash},[]byte{})
	hash:=sha256.Sum256(headers)
	b.Hash =hash[:]  //保存Hash结果在当前块的Hash中
}

构建创世区块

首先我们说下生活中的火车,它是由火车头和一节一节的车厢组成。如果没有火车头,后面车厢也就无法行驶。在区块链中,为了能够构建一条区块链,我们也必须要一个“火车头”,就是第一个区块,这个区块就是“创世区块”。

func NewGenesisBlock() *Block  {
	return  NewBlock(0,[]byte("first block"),[]byte{})
}
}

区块链

区块链,顾名思义区块链就是一个一个有序的区块连接而成。它的本质就是一个一定结构的数据库。我们要特别注意前面的词“有序”。我们前面说过区块链就好像一个火车,在火车中链接每节车厢的是“铰链”,在区块链中它也有“铰链”来链接每个区块。这个“铰链”就是每个区块的当前Hash值。

区块链抽象图

定义区块链结构

在golang里可以使用数组、map来实现,数组可以保证顺序,map实现hash->block组合的映射 不过,针对目前的进度,我们不需要实现能过hash找到区块的方法,所以这里只用数组来保证顺序即可。

	type Blockchain struct {
  blocks []*Block
}

添加区块

我们首先把创世区块添加到区块链中,来引导后面的区块。

func  NewBlockchain()*Blockchain  {
	return &Blockchain{[]*Block{NewGenesisBlock()}}
}

然后根据上一个区块,添加新区块到链中。

func (bc *Blockchain)AddBlock(data string)  {
	prevBlock :=bc.blocks[len(bc.blocks)-1]
	newBlock :=NewBlock(prevBlock.Index+1,[]byte(data),prevBlock.Hash)
	bc.blocks =append(bc.blocks,newBlock)
}

运行

基本的区块链功能我们已经实现,下面我们就开看看它的效果。

func main(){
	bc :=NewBlockchain()
	bc.AddBlock("Joy send 1 BTC to Jay")
	bc.AddBlock("Jakc sent 2 BTC to Jay")

	for  _,block := range bc.blocks{
		fmt.Printf("Index :%d\n" ,block.Index)
		fmt.Printf("TimeStamp: %d\n",block.TimeStamp)
		fmt.Printf("Data: %s\n",block.Data)
		fmt.Printf("PrevHash: %x\n",block.PrevBlockHash)
		fmt.Printf("Hash: %x\n",block.Hash)
		fmt.Println("_____________________________")
	}

}}

运行结果

Index :0
TimeStamp: 1538560879
Data: first block
PrevHash: 
Hash: 4f72e1adeaf4c2c3953465dea1d7224280014128f972554724fe93cf2c6760a7
_____________________________
Index :1
TimeStamp: 1538560879
Data: Joy send 1 BTC to Jay
PrevHash: 4f72e1adeaf4c2c3953465dea1d7224280014128f972554724fe93cf2c6760a7
Hash: 070b089b9a7128dcfaca53258f004b3797e22c416c48faae1c6a3cefccc975c4
_____________________________
Index :2
TimeStamp: 1538560879
Data: Jakc sent 2 BTC to Jay
PrevHash: 070b089b9a7128dcfaca53258f004b3797e22c416c48faae1c6a3cefccc975c4
Hash: da1244af0658655ac8f82fec235acfe5dab47ce0f58b9afe75ac821c406c1dc6
_____________________________

总结

本篇文章介绍了怎么创建简单的区块链原型:只有一个数组来维护的链,每个块都拥有前一个块的hash值来保证彼此的连接。但是我们还有很多没有实现,比如说区块验证、分叉主链选择、共识算法等。

你可能感兴趣的:(#,goland实现区块链)