前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用Go构建区块链 第1部分:基本原型

使用Go构建区块链 第1部分:基本原型

作者头像
银河1号
发布2019-04-12 10:09:37
4400
发布2019-04-12 10:09:37
举报
文章被收录于专栏:银河系资讯银河系资讯

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, DataPrevBlockHash),并将它们相互拼接起来,然后在拼接后的结果上计算一个 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[:]

}

接下来,遵循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

}

这是我们的第一个区块链!我从没想过会这么容易?

现在让我们可以添加块:

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

我们构建了一个非常简单的区块链原型:它只是一个区块数组,每个区块都与前一个区块连接。实际的区块链显然复杂得多。在我们的区块链中添加新区块很容易而且很快,但在实际区块链中添加新区块需要一些工作:在获得添加区块的权限之前必须执行一些繁重的计算(这种机制称为工作量证明)。此外,区块链是一个没有单一决策者的分布式数据库。因此,必须由网络的其他参与者确认和批准新的区块(该机制称为共识)。我们的区块链中还没有交

在以后的文章中,我们将介绍这些功能。

(未经同意,请勿转载)

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-02-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 银河系1号 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Introduction
  • Block
  • Blockchain
  • Conclusion
相关产品与服务
区块链
云链聚未来,协同无边界。腾讯云区块链作为中国领先的区块链服务平台和技术提供商,致力于构建技术、数据、价值、产业互联互通的区块链基础设施,引领区块链底层技术及行业应用创新,助力传统产业转型升级,推动实体经济与数字经济深度融合。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档