内容简介:区块链是21世纪最具革命性的技术之一,至今仍在发展,很多潜力尚未完全实现。从本质上讲,区块链只是一个分布式数据库。但是它的独特之处在于它不是私人数据库,而是公共数据库,也就是说,使用它的每个人都有完整或部分数据副本。只有在数据库的其他管理员同意的情况下才能添加新记录。此外,正是由于区块链才使加密货币和智能合约成为可能。在本系列文章中,我们将构建一个基于简单区块链实现的简化加密货币。让我们从“区块链”的“区块”部分开始。在区块链中,区块是用来存储有价值信息的。实际上,交易信息是所有加密货币的价值所在。除此之外
Introduction
区块链是21世纪最具革命性的技术之一,至今仍在发展,很多潜力尚未完全实现。从本质上讲,区块链只是一个分布式数据库。但是它的独特之处在于它不是私人数据库,而是公共数据库,也就是说,使用它的每个人都有完整或部分数据副本。只有在数据库的其他管理员同意的情况下才能添加新记录。此外,正是由于区块链才使加密货币和智能合约成为可能。
在本系列文章中,我们将构建一个基于简单区块链实现的简化加密货币。
Block
让我们从“区块链”的“区块”部分开始。在区块链中,区块是用来存储有价值信息的。实际上,交易信息是所有加密货币的价值所在。除此之外,区块包含一些技术信息,如版本,当前时间戳和前一个块的哈希值。
在本文中,我们不打算实现像比特币规范中描述的那种区块,而是将使用它的简化版本,它只包含重要信息。这是它的样子:
type Block struct { Timestamp int64 Data []byte PrevBlockHash []byte Hash []byte }
Timestamp字段是当前时间戳(创建区块时),Data字段是区块中包含的实际有价值的信息,PrevBlockHash字段存储前一个区块的哈希值,Hash字段是当前区块的哈希值。在比特币规范中Timestamp, PrevBlockHash, 和 Hash是块头,它形成一个单独的数据结构,Data是另一个数据结构。我们为了简单起见将它们混合在了一起。
那么我们如何计算哈希?哈希计算方法是区块链的一个非常重要的特征,正是这个特征使区块链变得安全。问题在于计算哈希是一个计算上很困难的操作,即使在快速计算机上也需要一些时间(这就是人们购买功能强大的GPU来挖掘比特币的原因)。这是一种有意的架构设计,这使得添加新的区块变得困难,从而防止它们在添加后进行修改。我们将在以后的文章中讨论并实现这种机制。
目前,我们仅取了 Block
结构的部分字段( Timestamp
, Data
和 PrevBlockHash
),并将它们相互拼接起来,然后在拼接后的结果上计算一个 SHA-256,然后就得到了哈希.
Hash = SHA256(PrevBlockHash + Timestamp + Data)
在 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[:] }
接下来,遵循Golang约定,我们将实现一个简化创建区块的函数:
func NewBlock(data string, prevBlockHash []byte) *Block { block := &Block{time.Now().Unix(), []byte(data), prevBlockHash, []byte{}} block.SetHash() return block }
这就是区块!
Blockchain
现在让我们实现一个区块链。从本质上讲,区块链只是一个具有特定结构的数据库:它是一个有序的反向链接列表。这意味着区块以插入顺序存储,并且每个区块都链接到前一个区块。这种结构允许快速获取链中的最新区块并通过其散列(有效地)获得区块。
在 Golang 中,可以通过一个 array 和 map 来实现这个结构:array 存储有序的哈希(Golang 中 array 是有序的),map 存储 hash -> block 对(Golang 中, map 是无序的)。 但是在基本的原型阶段,我们只用到了 array,因为现在还不需要通过哈希来获取区块。
type Blockchain struct { blocks []*Block }
这是我们的第一个区块链!我从没想过会这么容易:wink:
现在让我们可以添加块:
func (bc *Blockchain) AddBlock(data string) { prevBlock := bc.blocks[len(bc.blocks)-1] newBlock := NewBlock(data, prevBlock.Hash) bc.blocks = append(bc.blocks, newBlock) }
结束!不过,就这样就完成了吗?
要添加新的区块,我们需要一个现有的区块,但是我们的区块链中没有区块!因此,在任何区块链中,必须至少有一个区块,这个区块,也就是链中的第一个区块,通常叫做创世区块( genesis block ). 让我们实现一个方法来创建创世区块:
func NewGenesisBlock() *Block { return NewBlock("Genesis Block", []byte{}) }
现在,我们可以实现一个函数来创建有创世区块的区块链:
func NewBlockchain() *Blockchain { return &Blockchain{[]*Block{NewGenesisBlock()}} }
让我们检查下区块链是否正常工作:
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() } }
Output:
Prev. hash: Data: Genesis Block Hash: aff955a50dc6cd2abfe81b8849eab15f99ed1dc333d38487024223b5fe0f1168 Prev. hash: aff955a50dc6cd2abfe81b8849eab15f99ed1dc333d38487024223b5fe0f1168 Data: Send 1 BTC to Ivan Hash: d75ce22a840abb9b4e8fc3b60767c4ba3f46a0432d3ea15b71aef9fde6a314e1 Prev. hash: d75ce22a840abb9b4e8fc3b60767c4ba3f46a0432d3ea15b71aef9fde6a314e1 Data: Send 2 more BTC to Ivan Hash: 561237522bb7fcfbccbc6fe0e98bbbde7427ffe01c6fb223f7562288ca2295d1
Conclusion
我们构建了一个非常简单的区块链原型:它只是一个区块数组,每个区块都与前一个区块连接。实际的区块链显然复杂得多。在我们的区块链中添加新区块很容易而且很快,但在实际区块链中添加新区块需要一些工作:在获得添加区块的权限之前必须执行一些繁重的计算(这种机制称为工作量证明)。此外,区块链是一个没有单一决策者的分布式数据库。因此,必须由网络的其他参与者确认和批准新的区块(该机制称为共识)。我们的区块链中还没有交易!
在以后的文章中,我们将介绍这些功能。
英文原文: https://jeiwan.cc/posts/building-blockchain-in-go-part-1/
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。