区块链算法及Go语言实现

索引:
理论部分
构建一个自己的区块链
1.创建区块
2.创建区块链
3.http server暴露区块链接口

代码传送门:https://github.com/Bing0514/simpleBlockChain

理论部分

区块链就是一种特殊的分布式数据库,没有中间节点,每个节点都是平等的,可以先任何一个节点写入数据,每个节点都是平等的因此请求的数据会快速同步到整个网络的所有节点,这个网络没有中心,没有管理员,每个节点都会写入交易数据,并且只能增查,不支持改删。

目前区块链主要分为三类:

公有链 – 任何人都能读取、交易等操作,如比特币、以太坊等
私有链 – 一个公司和组织内使用,一般是开发节点、测试节点
联盟链 – 主要针对有竞争有需要合作的场景,其共识过程受到预选节点控制的区块链 如Fabric R3联盟(世界各大银行组成) EEA(以太坊企业联盟) 阳光链等

解决的问题:

价值传递问题 – 交易双方认可的有用的物品进行交互转移,特点是转移的时候转让方必须消失物品,受让方必须接受到物品,在现实世界这是很容易的,但是在互联网中很难实现,互联网中更多的是数据的传递而非真正的价值,因此要引入第三方,比如支付宝等等,这样一来对第三方有很强的依赖性。在区块链中,人们通过区块链记账来解决互联网中一份价值复制多份的问题

特点:

不可篡改:只能增查,不支持改删
可追溯:公开透明(注意,可追溯不代表是数据是真实的)
去中心化

区块链的六层架构

应用层 – 封装了区块链的各种应用场景和案例
合约层 – 封装各类脚本和智能合约,是区块链可编程的基础
激励层 – 主要应用在公有链中,激励遵守规则的节点,惩罚不遵守规则的节点(在某些区块链系统中可能不存在)
共识层 – 网络节点的共识区块算法,决定了记账方式
网络层 – 数据传播、数据验证机制、自动组网功能等
数据层 – 底层数据区块链式结构个公私钥、时间戳技术等(最核心最基础)
应用层通过RPC与区块链其他部分进行交互,分开部署。

区块链的链式结构

最基本的构成单元是区块,一个区块由区块头和区块体构成,区块头中最重要的一个元素是父区块的hash,每个元素都有父区块的hash相当于有了一个父区块的指针,把一个一个的区块连接起来,在链式结构中,第一个区块叫做创世区块,这个区块只有数据没有父区块hash值。每个每个hash值都是通过hash函数计算得来的。

hash函数的特点是:

  • 确定性:同样的输入,无论计算多少次都是一定的
  • 单向性:反推困难
  • 隐秘性:抗暴力破解
  • 抗篡改:改变一个比特,其hash值的变化非常大
  • 抗碰撞:hash值重复可能性非常小
    hash函数的实现:

MD系列

  • SHA系列,推荐使用SHA256,SHA3
  • 综上区块链其实很简单就是这样的结构:


    mt845650.0318_waldman_figure9_hiresen-usmsdn.10-2.png

构建一个自己的区块链

  • 实现链式结构
  • 实现一个http server,对外暴露读写接口,从而可以通过http请求来读写链上数据
    目录结构:


    Captuqwere.png

步骤:

1.创建区块 block.go

package demochain
 
import (
   "crypto/sha256"
   "encoding/hex"
   "time"
)
 
type Block struct {
   //区块头
   Index int64 // 区块编号 - 代表区块在区块链中的位置
   Timestamp int64 //区块时间戳 - 区块创建的时间
   PrevBlockHash string //上一个区块的hash值
   Hash string //当前区块的hash值
 
// 区块体
   Data string //区块数据
}
 
/**
计算hash
 */
func calculateHash(b Block) string{
   blockData := string(b.Index) + string(b.Timestamp) + b.PrevBlockHash + b.Data
   hashInButes := sha256.Sum256([]byte(blockData)) //blockData是一个字符串,注意这里要转换层字节切片
   return hex.EncodeToString(hashInButes[:])
}
 
/**
生成新的区块 - 数据是基于前一个区块的
 */
func GenerateNewBlock(preBlock Block, data string) Block{
   newBlock := Block{}
   newBlock.Index = preBlock.Index+1
   newBlock.PrevBlockHash = preBlock.Hash
   newBlock.Timestamp = time.Now().Unix()
   newBlock.Hash = calculateHash(newBlock)
   return newBlock
}
 
/**
生成创世区块
index是0
hash是一个空值
 */
func GenerateGenesesBlock() Block{
   preBlock := Block{} //这个父区块是不存在的,是为了函数复用
   preBlock.Index = -1
   preBlock.Hash = ""
   return GenerateNewBlock(preBlock,"Genesis Block")
}

2.创建区块链 blockchain.go

package core
 
import (
   "fmt"
   "log"
)
 
type Blockchain struct {
   Blocks []*Block
}
 
/**
新建一个区块链
 */
func NewBlockchain() *Blockchain {
   genesisBlock := GenerateGenesesBlock()
   blockchain := Blockchain{}
   blockchain.AppendBlock(&genesisBlock)
   return &blockchain
}
 
/**
写入一条数据
 */
func (bc *Blockchain)SendData(data string)  {
   preBlock := bc.Blocks[len(bc.Blocks) -1 ]
   newBlock := GenerateNewBlock(*preBlock,data)
   bc.AppendBlock(&newBlock)
}
 
func (bc *Blockchain) Print(){
   for _, block := range bc.Blocks{
      fmt.Printf("Index:%d\n", block.Index)
      fmt.Printf("Prev.Hash:%s\n", block.PrevBlockHash)
      fmt.Printf("Curr.Hash:%s\n", block.Hash)
      fmt.Printf("Data:%s\n",block.Data)
      fmt.Printf("Timestamp:%d\n",block.Timestamp)
      fmt.Println()
   }
}
 
/**
添加新的区块
 */
func (bc *Blockchain) AppendBlock(newBlock *Block)  {
   if len(bc.Blocks) == 0 {
      bc.Blocks = append(bc.Blocks,newBlock)
      return
   }
   if(isValid(*newBlock,*bc.Blocks[len(bc.Blocks) -1])){
      bc.Blocks = append(bc.Blocks,newBlock)
   }else {
      log.Fatal("invalid block")
   }
}
 
func isValid(newBlock Block, oldBlock Block) bool{
   if(newBlock.Index - 1 != oldBlock.Index){
      return false
   }
   if newBlock.PrevBlockHash != oldBlock.Hash{
      return false;
   }
   if calculateHash(newBlock) != newBlock.Hash{
      return false;
   }
   return true;
}

接下来创建一个main来运行

package main
 
import "demochain/core"
 
func main()  {
   bc := core.NewBlockchain()
   bc.SendData("Send 1 BTC to Jacky")
   bc.SendData("Send 1 EOS to Jack")
   bc.Print()
}

运行结果

InkedCapture_LI-768x635.jpg

说明(这里前面都提到过):

第一个index为0的区块是创世区块,是没有父区块的hash的
可以看到第一个区块到第二个区块到第三个区块到之后的区块都是通过之前一个区块的hash来生成自己的hash的,这就是为什么叫做区块链的链

3.创建http server

这里我们让这个区块链通过API暴露出来可以被写入数据和读取数据

package main
 
import (
   "demochain/core"
   "encoding/json"
   "io"
   "net/http"
)
 
var blockchain *core.Blockchain
 
func run()  {
   http.HandleFunc("/blockchain/get", blockchainGetHandler)
   http.HandleFunc("/blockchain/write",blockchainWriteHandler)
   http.ListenAndServe("localhost:8641",nil)
}
 
func blockchainGetHandler(w http.ResponseWriter, r *http.Request)  {
   bytes,error := json.Marshal(blockchain)
   if error != nil{
      http.Error(w, error.Error(),http.StatusInternalServerError)
      return
   }
   io.WriteString(w, string(bytes))
}
 
func blockchainWriteHandler(w http.ResponseWriter, r *http.Request)  {
   blockData := r.URL.Query().Get("data")
   blockchain.SendData(blockData)
   blockchainGetHandler(w,r)
}
 
func main()  {
   blockchain = core.NewBlockchain()
   run()
}

运行这个main方法,启动一个http server,首先看到的是创世区块,因此这个时候还没有写入数据


2.png

然后写入两个区块数据看效果


5.png

本文作者熊冰,个人网站Bing的天涯路,转载请注明出处。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,843评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,538评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,187评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,264评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,289评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,231评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,116评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,945评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,367评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,581评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,754评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,458评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,068评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,692评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,842评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,797评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,654评论 2 354