简介:
区块链是21世纪最具革命性的技术之一,此项技术依然在发展当中,它的潜力尚未被完全发掘。本质上,区块链仅仅是一个分布式的数据库。但是区块链的独特之处在于它不是一个私有的数据库,而是一个公有的数据库。例如:使用它的人(节点),保存一个它的完全副本或者至少部分副本。并且,一个新的纪录被加入到区块链需要其他节点达成共识。另外区块链使得加密货币和智能合约成为可能。
在系列文章中,我将基于区块链实现一个的简单的加密货币。
区块:
让我们先从区块链中“区块"的概念入手。在区块链中区块是用来存储有价值的信息的。例如:比特币的区块存储交易,这也是所有加密货币的本质。除此以外,一个区块还包含一些诸如版本号,当前时间戳以及前一个区块的哈希值等技术信息。在这篇文章中,我们不打算实现区块链中或者比特币中所描述的区块,取而代之,我们实现一个简化的版本,它只包含一些关键的信息,如下代码所示。
type Block struct {
Timestamp int64
Data []byte
PrevBlockHash []byte
Hash []byte
}
Timestamp指的是区块被创建时的时间,Data是区块中包含的真正有价值的信息。PrevBlockHash存储前向区块的哈希值。Hash为此区块的哈希值。在比特币中Timestamp,PrevBlockHash,Hash都是在区块头中,而交易(相当于我们这个版本中的Data)是一个与此隔离的数据结构。这里为了简化难度,我们将它们混合在一起。
那么我们如何计算哈希值?哈希值的计算方法是区块链非常重要的特性,正是这种特性保证着区块链的安全。然而计算哈希值是计算困难性的操作,即使是非常快速的计算机也需要耗费一些时间,这也是为什么人们买功能更加强大的GPU矿机去挖比特币的原因。这种有目的的架构设计使得添加一个区块变得非常困难,从而可以防止矿工在添加一个区块后修改它(想修改一个区块成功必须连续获得记账权)。我们将在以后的文章中讨论并实现这种机制。
现在我们将区块中的这些字段组合起来,并为它们计算一个hash值。如下面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
}
区块链
现在,我们来实现一个区块链。本质上,区块链是一个有序的,链表结构的数据库。每个区块以插入的顺序存储并且每个区块有一个哈希指针指向前一个区块。这种结构允许我们快速的获取区块链中最新的区块以及高效的根据hash值获取一个区块。
这种结构可以用Golang中的数组和map实现:数组可以保存有序的hash值(在Go中数组是有序的),map可以保存hash-block对(map是无序的)。但是在我们将要实现的区块链原型中我们仅仅使用数组,因为我们暂时不需要拥有“根据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()}}
}
好了,让我们测一下我们的区块链能不能正常工作:
func main() {
//创建区块链
bc := NewBlockChain()
//等待2s钟添加一个区块
time.Sleep(time.Duration(2)*time.Second);
bc.AddBlock("Send 1 BTC to Ivan")
//等待2s添加另一个区块
time.Sleep(time.Duration(2)*time.Second);
bc.AddBlock("Send 2 more BTC to Ivan")
//打印出区块中的内容
for _, block := range bc.blocks {
fmt.Printf("Prev. hash : %x",block.PrevBlockHash)
fmt.Printf("Data: %s",block.Data)
fmt.Printf("Hash: %x",block.Hash)
fmt.Printf("Timestamp: %d",block.Timestamp)
fmt.Println()
fmt.Println()
}
}
结果:
总结:
上述内容中我们设计了一个简单的区块链原型:它仅仅是区块的一个数组,每一个区块与他的前一个区块保留某种联系。真正的区块链项目如比特币比这个要复杂的多。在我们的区块链中添加一个区块十分简单快速,但是在真正的区块链中添加区块需要完成一些工作:获得添加区块的权限前,需要完成一些非常重的计算工作(这种机制我们称作PoW,即工作量证明)。因此区块链是一个去中心化的分布式数据库。所以,一个区块必须被其他的P2P网络节点确认和承认(这种机制被称作共识)。目前为止,我们的区块链中还没有任何交易。
在接下来的系列文章中,我们会实现上面所说的这些特性。
欢迎关注,评论和转发。
-迈小步不停步,回头看看一大步-
有疑问加站长微信联系(非本文作者)