区块链是21世纪重要的技术革命之一,虽然还没有成熟,但是仍然有很多潜力尚待发掘。基于区块链的本质,它就是一个分布式记录数据库。但是和私有数据库不同的是,区块链是公开的(私有链在域内也是公开的),也就是说每一个使用它的人都会有完整或者说部分副本。而且新的记录要增加的话,需要得到链中其它拥有者的同意。而且,区块链使得加密货币和智能合约成为可能。这一系列文章,将会阐述和实现基于简单的区块链来生成简单的加密货币。

Block 块/区块

先从“区块链”中的“区块”说起。在区块链中,块存储了变量信息,比如,比特币的区块存储了交易、还有加密货币除了这些,区块包含了一些技术信息,比如版本、时间戳、还有排在前面的一个区块的hash值 
1. Timestamp 时间戳也即是在区块被创建时的时间 
2. Data 就是这个区块存储的变量信息 
3. PrevBlockHash 前一区块的hash值 
4. Hash 是当前区块的hash值 
和比特币分开存储的数据结构不同的是 Timestamp、PrevBlockHash、Hash是区块的头(headers)信息,交易(transactions,我们这里转成Data来称呼)是在数据(data)信息中。这里把这些概念放在一块,方便些:

块代码结构

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

hash

那为什么要计算hash呢?计算hash值在区块链中是非常重要的特点,这使得区块链是安全的。因为计算有指定特征的hash非常困难,即使在牛逼的计算机中也要花上一些时间计算出来(所以有的人就买更适合简单浮点运算的GPU去挖Bitcoin矿)。这么做是故意的,因为这样可以增加创建新块的难度,导致增加了区块的节点无法在增加后改动这个区块,而改动后,这个区块也就失效了,不被大家承认。 区块链的hash算法。为了简单,我们现在基于SHA-256构造SetHash方法,

func (b *Block) SetHash() {
  timestamp := []byte(strconv.FormatInt(b.Timestamp, 10))
  headers := bytes.Join([][]byte{b.PrevBlockHash, b.Data, timestamp}, []byte{})
  hash := sha256.Sum256(headers)
  b.Hash = hash[:]
}

创建区块

实现一个简单的创建区块方法:

func NewBlock(data string, prevBlockHash []byte) *Block {
  block := &Block{time.Now().Unix(), []byte(data), prevBlockHash, []byte{}}
  block.SetHash()
  return block
}

blackchain 区块链

开篇说过,区块链的本质就是一个一定结构的数据库。它是一个有序的、首尾相连的链状列表,区块们都是顺序、每一个块都连接着前面的一个块。这个结构使得可以在区块链中快速找到最后一个区块,尤其是可以通过hash值找到区块。

定义简单的区块链

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

type Blockchain struct {
  blocks []*Block
}

然后给区块链添加增加区块的能力:

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

创世区块

为了创建新的区块,需要一个已经存在的区块,但是现在还没有任何一个区块。而在区块链中,第一个区块,就是“创世区块”。

func NewGenesisBlock() *Block {
  return NewBlock("Genesis Block", []byte{})
}

使用创世区块来引导区块链

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

运行

现在可以在命令行时输入 go run *.go运行创建区块链

func main() {
  bc := NewBlockchain()
bc.AddBlock("Send 1 BTC to Ivan")
  bc.AddBlock("Send 2 more BTC to Ivan")
for _, block := range bc.blocks {
    fmt.Printf("Prev. hash: %x\n", block.PrevBlockHash)
    fmt.Printf("Data: %s\n", block.Data)
    fmt.Printf("Hash: %x\n", block.Hash)
    fmt.Println()
  }
}

控制台会输出区块链的内部信息:

Prev. hash:
Data: Genesis Block
Hash: 4f729464de88e6a01c59a54707b11d3efd5fb036637fa81f4fbcce437b7b0738
Prev. hash: 4f729464de88e6a01c59a54707b11d3efd5fb036637fa81f4fbcce437b7b0738
Data: Send 1 BTC to Ivan
Hash: 53655b661290d9d4c9973618dfd2b5cb71c8c2981b5c955fa70af5d6a30b02be
Prev. hash: 53655b661290d9d4c9973618dfd2b5cb71c8c2981b5c955fa70af5d6a30b02be
Data: Send 2 more BTC to Ivan
Hash: 22cbee453308893beca8fd023c77d61a05eca29db99272a2795d0ae7af7d306d

本章总结

我们创建了简单的区块链原型:只有一个数组来维护的链,每个块都拥有前一个块的hash值来保证彼此的连接。真正的区块链自然是要比这里的复杂得多的。这里的区块链产生很简单也很快,但是真正的区块链产生需要做很多工作,如果要获得一个区块,那么需要做大量而繁重的计算,这一机制被称为工作量证明(Proof-of-Work)。区块链是分布式的且没有决定者(去中心化)。这就是说,新的区块增加需要得到其它网络中参与运算的节点认可(共识)。在我们上面的例子中,还没有一笔交易,所以,不算正式意义上的区块链。

 

2.1 基本概念

相关文章:

  • 2021-09-23
  • 2021-07-30
  • 2022-02-10
  • 2021-06-01
猜你喜欢
  • 2021-06-15
  • 2021-11-06
  • 2021-08-23
  • 2021-05-23
相关资源
相似解决方案