当前位置:   article > 正文

Go语言实现区块链与加密货币-Part1(基本原型、工作量证明、持久化)_newblock(data string, preblockhash []byte) *block

newblock(data string, preblockhash []byte) *block

区块链(Blockchain)是21世纪最具革命性的技术之一,它仍然处于不断成长的阶段,而且还有很多潜力尚未显现。作为比特币的底层技术,它本质上只是一个分布式数据库。不过使它独一无二的是,区块链是一个公开的而不是私人的数据库,每个使用它的人都有一个完整或者部分的副本。只有经过其他“数据库管理员”的同意,才能向其中添加新的记录。此外,也正是由于区块链,才使得加密货币和智能合约成为现实。

本文将实现一个简化版的区块链,并基于此来构建一个简化版的加密货币。

准备工作:
1.Go语言(可选)教程以及环境安装:http://www.runoob.com/go/go-environment.html
2.安装数据库依赖包:$ go get -u github.com/boltdb/bolt
参考:
https://jeiwan.cc/
https://liuchengxu.gitbook.io/blockchain/
目的:
1.认识区块链,了解其基本数据结构;
2.理解共识算法PoW的基本原理和作用;
3.实现持久化和命令行接口。

1、基本数据结构

首先从 “区块” 谈起。在区块链中,真正存储有效信息的是区块(block)。而在比特币中,真正有价值的信息就是交易(transaction)。实际上,交易信息是所有加密货币的价值所在。除此以外,区块还包含了一些技术实现的相关信息,比如版本,当前时间戳和前一个区块的哈希。

不过,我们要实现的是一个简化版的区块链,而不是一个像比特币技术规范所描述那样成熟完备的区块链。所以在我们目前的实现中,区块仅包含了部分关键信息,它的数据结构如下:

//区块的数据结构
//Block 由区块头和交易信息两部分组成


type Block struct {
   
	Timestamp     int64   //当前时间戳
	Data          []byte  //区块实际存储的信息,也就是比特币中的交易信息
	PrevBlockHash []byte  //前一个块的哈希
	Hash          []byte  //当前块的哈希
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在我们的简化版区块中,还有一个 Hash 字段,那么,要如何计算哈希呢?哈希计算,是区块链一个非常重要的部分。正是由于它,才保证了区块链的安全。计算一个哈希,是在计算上非常困难的一个操作。即使在高速电脑上,也要耗费很多时间 (这就是为什么人们会购买 GPU,FPGA,ASIC 来挖比特币) 。这是一个架构上有意为之的设计,它故意使得加入新的区块十分困难,继而保证区块一旦被加入以后,就很难再进行修改。在接下来的内容中,我们将会讨论和实现这个机制。

目前,我们仅取了 Block 结构的部分字段(Timestamp, Data 和 PrevBlockHash),并将它们相互拼接起来,然后在拼接后的结果上计算一个 SHA-256,然后就得到了哈希。把这个功能用以下的SetHash函数来实现。

//设置当前块哈希
// Hash=sha256(PrevBlockHash+Data+Timestamp)
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[:]
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

接下来,按照 Golang 的惯例,我们会实现一个用于简化创建区块的函数 NewBlock:

//用于生成新块
//当前块的哈希会基于传入的参数Data 和PrevBlockHash计算得到
func NewBlock(data string, prevBlockHash []byte) *Block {
   
	block := &Block{
   
		Timestamp:		time.Now().Unix(), 
		PrevBlockHash:	prevBlockHash, 
		Hash:			[]byte{
   },
		Data:			[]byte(data) }
	
	block.SetHash()
	return block
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

有了区块,下面让我们来实现区块。本质上,区块链就是一个有着特定结构的数据库,是一个有序,每一个块都连接到前一个块的链表。也就是说,区块按照插入的顺序进行存储,每个块都与前一个块相连。这样的结构,能够让我们快速地获取链上的最新块,并且高效地通过哈希来检索一个块。
在 Golang 中,可以通过一个 array 和 map 来实现这个结构:array 存储有序的哈希(Golang 中 array 是有序的),map 存储 hash -> block 对(Golang 中, map 是无序的)。 但是在基本的原型阶段,我们只用到了 array,因为现在还不需要通过哈希来获取块。

//第一个区块链————这是一个Block 指针数组
type Blockchain struct {
   
	blocks []*Block
}
  • 1
  • 2
  • 3
  • 4
  • 5

现在,让我们能够给它添加一个区块:

//添加区块
//data就是交易
func (bc *Blockchain) AddBlock(data string) {
   
	prevBlock := bc.blocks[len(bc.blocks)-1]
	newBlock := NewBlock(data, prevBlock.Hash)
	bc.blocks = append(bc.blocks, newBlock)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

结束!不过,就这样就完成了吗?
为了加入一个新的块,我们必须要有一个已有的块,但是,初始状态下,我们的链是空的,一个块都没有!所以,在任何一个区块链中,都必须至少有一个块。这个块,也就是链中的第一个块,通常叫做创世块(genesis block)。(话说中本聪还在创世块中留下了经典名言) 让我们实现一个方法来创建创世块:

//创建创世区块
func NewGenesisBlock() *Block {
   
	return NewBlock("Genesis Block", []byte{
   })
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

现在,我们可以实现一个函数来创建一条有创世块的

//创建一个有创世块的区块链
func NewBlockchain() *Blockchain {
   
	return &Blockchain{
   []*Block{
   NewGenesisBlock()}}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

检查一下我们的区块链是否如期工作:

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()
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

以上涉及到的Go语言包:

package main

import (
"bytes"
"crypto/sha256"
"strconv"
"time"
"fmt"
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在命令行中运行结果如下:
在这里插入图片描述
我们创建了一个非常简单的区块链原型:它仅仅是一个数组构成的一系列区块,每个块都与前一个块相关联。真实的区块链要比这复杂得多。在我们的区块链中,加入新的块非常简单,也很快,但是在真实的区块链中,加入新的块需要很多工作:你必须要经过十分繁重的计算(这个机制叫做工作量证明),来获得添加一个新块的权力。并且,区块链是一个分布式数据库,并且没有单一决策者。因此,要加入一个新块,必须要被网络的其他参与者确认和同意(这个机制叫做共识(consensus))。还有一点,我们的区块链还没有任何的交易!

2、工作量证明(Proof-of-Work)

在上一节,我们构造了一个非常简单的数据结构 – 区块,它也是整个区块链数据库的核心。目前所完成的区块链原型,已经可以通过链式关系把区块相互关联起来:每个块都与前一个块相关联。
但是,当前实现的区块链有一个巨大的缺陷:向链中加入区块太容易,也太廉价了。而区块链和比特币的其中一个核心就是,要想加入新的区块,必须先完成一些非常困难的工作。在本文,我们将会弥补这个缺陷。
区块链的一个关键点就是,一个人必须经过一系列困难的工作,才能将数据放入到区块链中。正是由于这种困难的工作,才保证了区块链的安全和一致。此外,完成这个工作的人,也会获得相应奖励(这也就是通过挖矿获得币)。
这个机制与生活现象非常类似:一个人必须通过努力工作,才能够获得回报或者奖励,用以支撑他们的生活。在区块链中,是通过网络中的参与者(矿工)不断的工作来支撑起了整个网络。矿工不断地向区块链中加入新块,然后获得相应的奖励。在这种机制的作用下,新生成的区块能够被安全地加入到区块链中,它维护了整个区块链数据库的稳定性。值得注意的是,完成了这个工作的人必须要证明这一点,即他必须要证明他的确完成了这些工作。
整个 “努力工作并进行证明” 的机制,就叫做工作量证明(proof-of-work)。要想完成工作非常地不容易,因为这需要大量的计算能力:即便是高性能计算机,也无法在短时间内快速完成。另外,这个工作的困难度会随着时间不断增长,以保持每 10 分钟出 1 个新块的速度。在比特币中,这个工作就是找到一个块的哈希,同时这个哈希满足了一些必要条件。这个哈希,也就充当了证明的角色。因此,寻求证明(寻找有效哈希),就是矿工实际要做的事情。

2.1 哈希计算

获得指定数据的一个哈希值的过程,就叫做哈希计算。一个哈希,就是对所计算数据的一个唯一表示。对于一个哈希函数,输入任意大小的数据,它会输出一个固定大小的哈希值。下面是哈希的几个关键特性:
1.无法从一个哈希值恢复原始数据。也就是说,哈希并不是加密。
2.对于特定的数据,只能有一个哈希,并且这个哈希是唯一的。
3.即使是仅仅改变输入数据中的一个字节,也会导致输出一个完全不同的哈希。
在这里插入图片描述
在区块链中&

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/952736
推荐阅读
相关标签
  

闽ICP备14008679号