【区块链】Go 实现简单区块链

本文主要利用 Go 语言对区块链模型进行了简单的实现,通过 GoLand 创建链式结构和一个简单的 http server,对外暴露读写接口,运行 rpc 并以地址访问形式向区块链发送数据和读取数据。

简单区块链的实现大致步骤分为:

(1)创建 Block
(2)创建 Blockchain
(3)创建 Http server

在实现之前,首先通过 GoLand 创建 blockchainDemo 项目,并建立对应的 Block.goBlockchain.go 以及 Server.go 文件,具体的目录如下。

一、创建 Block

  • 创建 Block 文件
  • 创建 Block 结构体与相关函数
package core  import (  "crypto/sha256"  "encoding/hex"   "time")  type Block struct {  Index         int64  // 区块编号  Timestamp     int64  // 区块时间戳  PrevBlochHash string // 上一个区块哈希值  Hash          string // 当前区块哈希值  Data string // 区块数据  
}  // calculateHash 计算哈希值  
func calculateHash(b Block) string {  blockData := string(b.Index) + string(b.Timestamp) + b.PrevBlochHash + b.Data  hashInBytes := sha256.Sum256([]byte(blockData))  return hex.EncodeToString(hashInBytes[:])  
}  // GenerateNewBlock 创建新区块  
func GenerateNewBlock(preBlock Block, data string) Block {  newBlock := Block{}  newBlock.Index = preBlock.Index + 1  newBlock.PrevBlochHash = preBlock.Hash  newBlock.Timestamp = time.Now().Unix()  newBlock.Data = data  newBlock.Hash = calculateHash(newBlock)  return newBlock  
}  // GenerateGenesisBlock 创建世纪区块  
func GenerateGenesisBlock() Block {  preBlock := Block{}  preBlock.Index = -1  preBlock.Hash = ""  return GenerateNewBlock(preBlock, "Genesis Block")  
}

这里需要注意的是,在创建世纪区块时,考虑到对 GenerateNewBlock 函数的复用,因此,创建了一个 preBlock 来辅助世纪块的创建,实际区块链上世纪块前面不存在其他区块,且世纪块以 0 作为索引。

二、创建 Blockchain

  • 创建 Blockchain 文件
  • 创建 Blockchain 结构体及相关方法
package core  import (  "fmt"  "log")  type Blockchain struct {  Blocks []*Block  
}  // CreateBlockchain 创建区块链  
func CreateBlockchain() *Blockchain {  genesisBlock := GenerateGenesisBlock()  blockchain := Blockchain{}  blockchain.AppendBlock(&genesisBlock)  return &blockchain  
}  // SendData 向区块链添加数据  
func (bc *Blockchain) SendData(data string) {  preBlock := bc.Blocks[len(bc.Blocks)-1]  newBlock := GenerateNewBlock(*preBlock, data)  bc.AppendBlock(&newBlock)  
}  // AppendBlock 向区块链添加新区块  
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.PrevBlochHash != oldBlock.Hash {  return false  }  if calculateHash(newBlock) != newBlock.Hash {  return false  }  return true  
}  // Print 对区块链上的区块内容进行打印  
func (bc *Blockchain) Print() {  for _, block := range bc.Blocks {  fmt.Printf("Index: %d\n", block.Index)  fmt.Printf("Prev.Hash: %s\n", block.PrevBlochHash)  fmt.Printf("Curr.Hash: %s\n", block.Hash)  fmt.Printf("Data: %s\n", block.Data)  fmt.Printf("Timestamp: %d\n", block.Timestamp)  }  
}

三、创建 Http server

  • 创建 http server
  • 提供 API 访问接口
package main  import (  "blockchainDemo/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:8888", nil)  
}  // 读接口  
func blockchainGetHandler(w http.ResponseWriter, r *http.Request) {  bytes, err := json.Marshal(blockchain)  if err != nil {  http.Error(w, err.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.CreateBlockchain()  run()  
}

四、模型测试

在 GoLand 上运行 http server,从代码中可知监听端口为 8888,因此,读写操作对应的地址是:

  • http://localhost:8888/blockchain/get
  • http://localhost:8888/blockchain/write?data=Send 1 BTC to Me

参数 data 的内容可自定义

// 网页显示效果
{"Blocks":[{"Index":0,"Timestamp":1674227301,"PrevBlochHash":"","Hash":"90d7d6d9adc8a6dd4eca1e30d8c1a8556a8e3e508da81f30a9e520c2ee7124b0","Data":"Genesis Block"},{"Index":1,"Timestamp":1674227338,"PrevBlochHash":"90d7d6d9adc8a6dd4eca1e30d8c1a8556a8e3e508da81f30a9e520c2ee7124b0","Hash":"1a7c54ce0eaba45d5591640925405d90e74d9da5fa919b4e6eefa2447b2a4fb0","Data":"Send 1 BTC to Me"}]
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/31320.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【并发编程】线程池多线程异步去分页调用其他服务接口获取海量数据

文章目录 场景:解决方案 场景: 前段时间在做一个数据同步工具,其中一个服务的任务是调用A服务的接口,将数据库中指定数据请求过来,交给kafka去判断哪些数据是需要新增,哪些数据是需要修改的。 刚开始的设…

【Docker】配置指定大小的磁盘空间

背景 测试磁盘满时程序的运行情况 问题 如何使用 docker 来模拟磁盘满的情况 解决方法 创建指定大小的数据卷 volumedocker volume create --driver local --opt typetmpfs --opt devicetmpfs --opt osize50M my_volumn创建 docker 时,使用该数据卷docker run …

JS逆向系列之猿人学爬虫第14题-备而后动-勿使有变

文章目录 题目地址参数分析参考jspython 调用往期逆向文章推荐题目地址 https://match.yuanrenxue.cn/match/14题目难度标的是困难,主要难在js混淆部分。 参数分析 初始抓包有无限debugger反调试,可以直接hook 函数构造器过掉无限debugger Function.prototype.__construc…

Mirror网络库 | 说明

此篇为上文,下篇:Mirror网络库 | 实战 一、介绍 基于UNET,从2014年经过9年实战测试;服务器和客户端是一个项目;使用NetworkBehaviour而不是MonoBehaviour,还有NetworkServer和NetworkClient;Mi…

pdf怎么压缩到1m?这样做压缩率高!

PDF是目前使用率比较高的一种文档格式,因为它具有很高的安全性,还易于传输等,但有时候当文件体积过大时,会给我们带来不便,这时候简单的解决方法就是将其压缩变小。 想要将PDF文件压缩到1M,也要根据具体的情…

雅克比矩阵在机器人运动学中的应用

以六轴机械臂为例,设机械臂关节空间为q,位置矩阵为p,速度矩阵为v q [ q 0 , q 1 , q 2 , q 3 , q 4 , q 5 ] q[q_0,q_1,q_2,q_3,q_4,q_5] q[q0​,q1​,q2​,q3​,q4​,q5​] p [ x , y , z ] T [ f x ( q ) f y ( q ) f z ( q ) ] p[x,y,z…

ASP.NET Core中间件记录管道图和内置中间件

管道记录 下图显示了 ASP.NET Core MVC 和 Razor Pages 应用程序的完整请求处理管道 中间件组件在文件中添加的顺序Program.cs定义了请求时调用中间件组件的顺序以及响应的相反顺序。该顺序对于安全性、性能和功能至关重要。 内置中间件记录 内置中间件原文翻译MiddlewareDe…

微服务 云原生:基于 Gogs + Drone 实现 CI/CD 自动化

一般构建部署 以一个简单的前后端项目来说,分别编写前后端的 Dockerfile 文件并构建镜像,然后编写 docker-compose.yml 构建部署,启动运行。每次代码变更后都需重新手动打包、构建、推送。 一个简单的例子: 前端: 项…

【力扣每日一题】2023.8.7 反转字符串

目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 题目给我们一个字符数组形式的字符串,让我们直接原地修改反转字符串,不必返回。 给出的条件是使用O(1)的额外空间…

bash: sudo: command not found的解决方法 | 安装sudo

-bash: sudo: command not found的解决方法 https://www.cnblogs.com/pengpengboshi/p/16159443.html 报错 安装apt-get update报错由于没有公钥,无法验证下列签名: NO_PUBKEY A4B469963BF863CC解决办法是手动加入 (sudo可去掉)…

c# 全网最稳定 企业级 以太网客户端类库 具备即时更新状态,断线三次重拨,稳定收发。

源码下载,带示例 代码实现了一个基本的TCP客户端,能够连接到服务器并发送接收数据。当连接失败时,会进行重连,并在达到最大重连次数后终止连接。使用异步编程模型、实现事件模型以及重连机制。 ConnectAsync(): 这是一个异步方法,用于与服务器建立连接。在方法中,首先初始…

ARM架构银河麒麟docker,源码编译安装GDAL

docker中安装依赖 sudo apt-get update sudo apt-get install build-essential autoconf automake libtool sudo apt-get install libproj-dev libgeos-dev libjson-c-dev libpng-dev libjpeg-dev sudo apt-get install python3-dev sudo apt-get install python3.11-dev去官网…

IO密集时epoll还高效吗?

io特别密集时为什么 epoll 效率不高。原因是: 连接密集(短连接特别多),使用epoll的话,每一次连接需要发生epoll_wait->accpet->epoll_ctl调用,而使用select只需要select->accpet,减少了…

数组和字符串-字符串

最长公共前缀 题意: 给多个字符串,找最长前缀 解: 暴力匹配,先按字典序排序字符串,这样长度短的优先进行匹配,所得字符串就可能偏小 适合a aa aaa aaaa这样的数据,不过对于aa aab aabc aab…

python爬虫相关

目录 初识爬虫 爬虫分类 网络爬虫原理 爬虫基本工作流程 搜索引擎获取新网站的url robots.txt HTHP协议 Resquests模块 前言: 安装 普通请求 会话请求 response的常用方法 简单案例 aiohttp模块 使用前安装模块 具体案例 数据解析 re解析 bs4…

数据治理内容

https://space.bilibili.com/405479587 文章内容来源b站up主,语兴呀 数据治理内容 一.模型: 由于早期业务快速扩张,对元数据把控不到位,导致成熟期出现大量不合规模型 解决:数据标准:元数据补充 建设管控&…

基于长短期神经网络LSTM时间序列回归分析

​目录 背影 摘要 LSTM的基本定义 LSTM实现的步骤 基于长短期神经网络LSTM的回归分析 MATALB代码:基于长短期神经网络的回归分析,基于LSTM的回归预测资源-CSDN文库 https://download.csdn.net/download/abc991835105/88184633 效果图 结果分析 展望 参考论文 背影 LSTM神经…

AutoDL服务器的镜像版本太高,配置python3.7 tensorflow1.15版本的框架的步骤

1.选择一个实例,进入后端界面 2. 更新bashrc中的环境变量 conda init bash && source /root/.bashrc查看虚拟环境 conda info --envs可以看到此时有一个base的虚拟环境 但是它的python版本为3.8.10,无法安装tensorflow1.15,所以我们要创建一个…

PHP面向对象面试题

1、简述面对对象六大设计原则 ? 面向对象六大设计原则是一组指导软件设计的原则,它们有助于提高代码的可维护性、可扩展性和可重用性。这些原则是: 单一职责原则(Single Responsibility Principle,SRP)&a…

Ctfshow web入门 SSTI 模板注入篇 web361-web372 详细题解 全

CTFshow SSTI web361 笔记分享 一、代码块 变量块 {{}} 用于将表达式打印到模板输出 注释块 {##} 注释 控制块 {%%} 可以声明变量,也可以执行语句 {% for i in .__class__.__mro__[1].__subclasses__() %}{% if i.__name___wrap_close %}{% print i.__init__.…