【区块链100例】(1) 介绍区块链并通过go语言实现简单的区块链

说起足球不得不的提起这位退钱哥了!

在这里插入图片描述

在这里插入图片描述
2019年我老表获得首届欧洲国家联赛得分王奖杯!你看我老表笑的多开心!

在这里插入图片描述

最近举办的欧洲杯中,我们也可以看到区块链的身影哦(虽然是广告

1. 欧洲杯与区块链

6月10日,欧足联(UEFA) 在官方网站宣布,蚂蚁集团旗下蚂蚁链成为2020欧洲杯全球合作伙伴。欧足联与蚂蚁链签署了一项为期五年的合作协议,表示将共同探索应用区块链等技术加速足球产业数字化转型,为全球球迷提供更好更丰富的观赛体验。

在这里插入图片描述

得分王奖杯的设计师周一然介绍
" 足球是全世界通用的语言,而区块链也是一种建立人与人之间信任的‘共识语言’,两者十分契合。”
在这里插入图片描述

2. 区块链简介

2.1 概念

狭义来说

区块链是一种按照时间顺序将数据区块以顺序相连的方式组合成的一种链式数据结构,并以密码学方式保证的不可篡改和不可伪造的分布式账本。

广义来说

区块链技术是利用块链式数据结构来验证和存储数据、利用分布式节点共识算法来生成和更新数据、利用密码学的方式保证数据传输和访问的安全性利用由自动化脚本代码组成的智能合约来编程和操作数据的一种全新的分布式基础架构与计算范式

2.2 基础技术

2.2.1 哈希运算

区块链账本数据主要通过父区块哈希值组成链式结构来保证不可篡改性。

哈希算法(散列算法)

主要功能:把任意长度的输入通过一定的计算,生成一个固定长度的字符串,输出的字符串称为该输入的哈希值。

例子:
在百度随便找一个在线Hash算法
在这里插入图片描述
这里有很多种哈希算法!我们就用SHA-256为例子!
在这里插入图片描述
Go语言代码实现:
MD5

package main
import(
	"fmt"
    "crypto/md5"
    "encoding/hex"
)
func main(){
    //方法一
    data:=[]byte("hello world")
    s:=fmt.Sprintf("%x",md5.Sum(data))
    fmt.Println(s)
    //方法二
    h:=md5.New()
    h.Write(data)
    s= hex.EncodeToString(h.Sum(nil))
    fmt.Println(s)
}

SHA-256

package main
import(
	"fmt"
    "github.com/nebulasio/go-nebulas/crypto/hash"
    "encoding/hex"
	"crypto/sha256"    
)

func main(){
    //方法一 一个方法直接输出
    data:=[]byte("hello world")
    hash:=hash.Sha256(data)
    fmt.Println(hex.EncodeToString(hash))
    sha256.New()
    //方法二 按照步骤一步一步输出
    h:= sha256.New() //创建sha256算法
    h.Write(data)  //用sha256算法对参数a进行加密,得到8个变量
    hashTemp := h.Sum(nil)//将8个变量相加得到最终hash
    fmt.Println(hex.EncodeToString(hashTemp))
}

特点:

  • 正向快速
    给定数据,可以在极短的时间内快速得到哈希值。
  • 输入敏感
    输入的信息如果发生了微小的变化,重新生成的哈希值与原来的哈希值也会有天壤之别
  • 逆向困难
    无法短时间内根据哈希值计算出原始的输入信息,这个特性也是哈希算法安全的基础,也因此是现代密码学的重要组成。
  • 强抗碰撞性
    不同的输入很难可以产生相同的哈希输出。

另外:

  • 通过哈希构建的区块链的链式结构,实现了防篡改。

  • 通过哈希构建的默克尔树,实现内容改变的快速检测。

2.2.2 数字签名

数字签名在信息安全,包括身份认证、数据完整性、不可否认性以及匿名性有着重要应用,是吸纳带密码学的重要分支。签名隶属于公钥密码学。

签名过程:
发送方用自己的私钥对发送信息进行所谓的加密运算,得到一个hash值,该hash值就是签名。使用时需要将签名和信息发给接收方。接受者用发送方公开的公钥和接收到的信息对签名及逆行验证,通过认证,说明接受到的信息是完整的,准确的,否则说明消息来源不对。

数字签名具体过程:

  1. 发送方A对原始数据通过哈希算法计算数字摘要,使用非对称密钥对中的私钥对数字摘要进行加密,这个加密后的数据就是数字签名。
  2. 数字签名与A的原始数据一起发送给验证签名的任何一方。

验证数字签名的流程:

  1. 首先,签名的验证方,一定要持有发送方A的非兑成密钥对的公钥
  2. 在接收到数字签名与A的原始数据后,首先使用公钥,对数字签名进行解密,得到原始摘要值。
  3. 然后对A的原始数据通过同样的哈希算法计算摘要值,进而比对解密得到的摘要值与重新计算得到的摘要值是否相同,如果相同,则签名通过。

在这里插入图片描述

2.2.3 P2P网络

peer to peer,简称p2p,对等网络。处于p2p中的网络中的所有节点地位都是相等的,网络不依赖一个中心。

2.2.4 共识算法

概念

由于点对点网络下存在较高的网络时延,各个节点所观察到的事务先后顺序不可能完全一致。因此区块链系统需要设置一种机制对在差不多时间内发生的事务的先后顺序达成一致。这种对一个时间窗口内的事务的先后顺序达成共识的算法被称为共识机制。

  • 共识算法:节点依据共识规矩达成共识的计算算法
  • 共识规则:每个区块链里面都有经过精心设计的规则性协议,这些协议通过共识算法来保证共识规则得以正确执行。

相当于是生活中的法律

主要有以下这几种共识算法:

  • 工作量证明PoW:比特币BTC、以太坊ETH、以太坊经典ETC
  • 权益证明PoS:ADA艾达币、Peercoin点点币
  • 授权工作证明DPoS:EOS、Asch、Steem
  • 拜占庭容错算BFT:实用拜占庭容错PBFT、派生BFT
  • RAFT算法:ETCD

几种算法的对比

PoW PoS DPoS Raft PBFT
场景 公链 公链、联盟链 公链、联盟链 联盟链 联盟链
去中心化 完全 完全 完全 半中性化 半中性化
记账节点 全网 全网 选出若干代表 选出一个Leader 动态决定
响应时间 10分钟 1分钟 3秒左右 秒级 秒级
存储效率 全账本 全账本 全账本 全账本 全账本+部分账本
吞吐量 约7TPS 约15TPS 约300TPS或更高 几千甚至上万 约10000TPS或更高
容错 50% 50% 50% 50% 33%

2.2.5 智能合约

定义:

简单来说,智能合约是一种在满足一定条件时,就自动执行的计算机程序。
例如自动售货机可以看作是一个智能合约的系统。客户需要选择商品并完成

特点:

  1. 计算机程序的if-then语句
  2. 条约达成时自动执行
  3. 数字化的合同
  4. 计算系统自动执行条款

特征:

  • 数据透明:区块链上的数据对参与方是公开透明的,数据处理也是公开透明的。
  • 不可篡改:区块链本身的所有数据不可篡改,区块链上的智能合约代码以及运行产生的数据输出也是不可篡改的。
  • 永久运行:支撑区块链网络的节点往往达到数百甚至上千,部分节点的失效并不会导致智能合约的停止,其可靠性理论上接近于永久运行。

构成:

  • 参与方:参与数字资产交易的人或是组织。
  • 资产:具备一定价值而作为交易标得地事物,可以是具体的可以是抽象的。
  • 交易:参与方对资产进行查询,转移等操作的过程。
  • 账本:记录资产的归属及其交易事实的数据库。

在这里插入图片描述

2.3 特点

2.3.1 透明可信

  1. 人人记账保证人人获取完整信息,从而实现信息透明。
  2. 节点间决策过程共同参与,共识保证可信性

2.3.2 防篡改可追溯

防篡改:交易一旦在全网范围内经过验证并添加至区块链,就很难被修改或者抹除。

可追溯:是指区块链上发生的任意一笔交易都是完整记录的,我们可以针对某一状态在区块链上追查与其相关的全部历史交易。

2.3.3 隐私安全保障

由于区块链系统中的任意节点都包含了完整的区块校验逻辑,所以任意节点都不需要依赖其他节点完成区块链中交易的确认过程,也就是无需额外地信任其他节点。

2.3.4 系统高可靠

  1. 每个节点对等地维护一个账本并参与整个系统地共识,一个节点出现故障,整个系统也能够正常运行
  2. 区块链系统支持拜占庭容错。传统地分布式系统虽然也具有高可靠特性,但是通常只能容忍系统内的节点发生崩溃现象,或者出现网络分区的问题,而系统一旦被攻克,或者说修改了节点的信息处理逻辑,则整个系统都将无法正常工作。

3. 简单代码实现区块链

区块链的区块所需要的字段

字节 字段 说明
4 版本 区块版本号,表示本区块遵守的验证规则
32 父区块头哈希值 前一区块的Merkle树根的哈希值,同样采取SHA256计算
32 Merkle根 该区块中交易的Merkle树根的哈希值,同样采用SHA256计算
4 时间戳 该区块产生的近似时间,精确到秒的UNIX时间戳,必须严格大于前11各区块的时间的中值,同时全节点也会拒接那些超过自己两个小时的时间戳的区块
4 难度目标 该区块工作量证明算法的难度目标,已经使用特定算法编码
4 Nonce 未来找到满足难度目标所设定的随机数,为了解决32为随机数在算力飞升的情况下不够用的问题,规定时间戳和coinbase交易信息均改变,以此扩展nonce的位数

**注意:**区块不存储hash值,节点接受区块后独立计算并存储在本地。

3.1 区块相关:

  1. 定义一个区块的结构Block

    区块头:6个字段
    区块体:字符串表示data

/*
1.定义一个区块的结构Block
a.区块头:6个字段
b.区块体:字符串表示data
*/
//区块
type Block struct {
   Version int64   //版本
   PerBlockHash []byte //前一个区块的hash值
   Hash []byte //当前区块的hash值,是为了简化代码
   MerKelRoot []byte  //梅克尔根
   TimeStamp int64  //时间抽
   Bits int64  //难度值
   Nonce int64 //随机值

//区块体
   Data []byte  //交易信息
}
  1. 提供一个创建区块的方法
    NewBlock(参数)
提供一个创建区块的方法
NewBlock(参数)
*/
func NewBlock(data string ,prevBlockHash []byte) *Block {
   var block Block
   block = Block{
      Version:      2,
      PerBlockHash: prevBlockHash,
      //Hash:         []byte{},      //区块不存储hash值,节点接受区块后独立计算并存储在本地。
      MerKelRoot:   []byte{},
      TimeStamp:    time.Now().Unix(),
      Bits:         targetBits,
      Nonce:        0,
      Data:         []byte(data),
   }
   // block.SetHash()  //填充Hash
   PoW:= NewProofOfWork(&block)
   nonce , hash :=PoW.Run()
   block.Nonce=nonce
   block.Hash=hash
   return &block
}

另外别忘了创世块

func NewGensisBlock() *Block{
   return NewBlock("Genesis Block!",[]byte{})
}
  1. 定义一个工作量证明的结构ProofOfWork
    block | 目标值
/*
3. 定义一个工作量证明的结构ProofOfWork
block
目标值
*/
type ProofOfWork struct {
   block *Block
   target *big.Int   //目标值
}
  1. 提供一个创造PoW的方法

    NewProofOfWork(参数)

/*
4. 提供一个创造PoW的方法
NewProofOfWork(参数)
*/
const targetBits = 24 
func NewProofOfWork(block *Block) *ProofOfWork {  //工作量证明
   target := big.NewInt(1)  //000....001
   target.Lsh(target,uint(256-targetBits))  //将1向左移动 //ox00000010000000..00
   pow:=ProofOfWork{
      block:  block,
      target: target,
   }
   return &pow
}

func (pow *ProofOfWork) PrepareData(nonce int64) []byte {
   // 源码里面是要传二维切片 func Join(s [][]byte, sep []byte) []byte
   block := pow.block
   tmp :=[][]byte{
      IntToByte(block.Version),
      block.PerBlockHash,
      block.MerKelRoot,
      IntToByte(block.TimeStamp),
      IntToByte(block.Bits),
      IntToByte(block.Nonce),
   }
   data:=bytes.Join(tmp,[]byte{})    //之后再计算hash
   return data
}
  1. 提供一个计算哈希值的方法

    Run()

/*
5. 提供一个计算哈希值的方法
Run()
*/

func (pow *ProofOfWork)Run() (int64,[]byte) {
   //1.凭借数据
   //2.哈希值转成big.Int类型
   var hash [32]byte
   var nonce int64 = 0
   var hashInt big.Int
   fmt.Println("开始挖矿了!")
   fmt.Printf("难度 target hash : %xn" ,pow.target.Bytes())
   for nonce < math.MaxInt64  {
      data:=pow.PrepareData(nonce)
      hash = sha256.Sum256(data)
      // Cmp compares x and y and returns:
      //
      //   -1 if x <  y
      //    0 if x == y
      //   +1 if x >  y
      //
      hashInt.SetBytes(hash[:])
      if hashInt.Cmp(pow.target) == -1 {
         fmt.Printf("Found ,nonce :%d ,hash :%x n",nonce,hash)
      }else {
         //fmt.Printf("Not Found ,current nonce :%d ,hash :%x n",nonce,hash)
         nonce++
      }
   }
   return nonce,hash[:]
}
  1. 提供一个校验函数

    IsValid()

/*
6. 提供一个校验函数
IsValid()
*/

func (pow *ProofOfWork)IsValid() bool{
   var hashInt big.Int
   data := pow.PrepareData(pow.block.Nonce)
   hash:=sha256.Sum256(data)
   hashInt.SetBytes(hash[:])
   return hashInt.Cmp(pow.target) == -1  		//如果是-1就是找到了就是

}

3.2 区块链相关

  1. 定义一个区块链结构BlockChain

    ​ Block数组

/*
1. 定义一个区块链结构BlockChain
​   Block数组
*/
type BlockChain struct {
	blocks []*Block
}
  1. 提供一个创建BlockChain()的方法

    ​ NewBlockChain()

/*
2. 提供一个创建BlockChain()的方法
​   NewBlockChain()
*/
func NewBlockChain() *BlockChain {
	block := NewGensisBlock()
	return &BlockChain{blocks:[]*Block{block}} 		 //创建只有一个元素的区块链,初始化
}
  1. 提供一个添加区块的方法

    ​ AddBlock(参数)

/*
3. 提供一个添加区块的方法
​   AddBlock(参数)
*/
func (bc *BlockChain)AddBlock(data string)  {
	PerBlockHash := bc.blocks[len(bc.blocks)-1].Hash  	//这一个区块的哈希是前一块的哈希值
	block := NewBlock(data,PerBlockHash)
	bc.blocks = append(bc.blocks,block)
}

一个简单的区块链就实现了!
在这里插入图片描述

最后

小生凡一,期待你的关注。
在这里插入图片描述

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>