使用go语言构建区块链 Part1.基础原型

news/2025/2/22 18:55:15/

英文源地址

简介

区块链技术是21世纪最具变革型的技术之一,它仍处于成长阶段, 其潜力尚未完全实现.从本质上说, 区块链是一个分布式的记账数据库.但它的独特之处在于它不是一个私有数据库,而是一个公共数据库, 也就是说, 每个使用它的人都有它的完整或部分副本.而且,只有在征得其他数据库维护者的同意的情况下, 才能添加新记录.此外, 正是区块链使加密货币和智能合约成为可能.
在本系列文章中, 我们将构建一个基于简单区块链实现的简易的数字加密货币.

Block区块

让我们从’区块链’的区块部分开始. 在区块链中, 它是存储有价值信息的块.例如, 比特币区块存储交易, 这是任何加密货币的本质. 除此之外, 一个块还包含一些技术信息, 比如它的版本, 当前时间戳和前一个块的哈希值.
在本文中, 我们不打算实现区块链或比特币规范中描述的区块, 相反, 我们将使用它的简化版本, 其中只包含重要信息.它看起来是这样的.

type Block struct {Timestamp int64Data []bytePrevBlockHash []byteHash []byte
}

Timestamp是当前时间戳(区块创建的时间), Data时区块中包含的实际有价值的信息, PrevBlockHash存储前一个区块的哈希值, Hash是当前区块的哈希值.在比特币规范中, Timestamp, PrevBlockHash和Hash是区块头部, 它们形成一个独立的数据结构, 而transactions(我们例子中的Data)是一个独立的数据结构.为了简单起见, 我们把它们放在一起.
那么我们如何计算哈希呢?哈希值的计算方式是区块链非常重要的特征, 正式这个特点使得区块链安全.问题是计算哈希是一项计算密集型操作, 即使在高速计算机上也需要耗费一些时间(这就是为什么人们购买强大的GPU来挖矿比特币). 这是一个有意义的设计, 这使得添加新区块变得困难, 从而阻止了它们在添加后被修改.我们将在以后的文章中讨论并实现该机制.
现在, 我们将获取区块字段, 将它们连接起来, 并在连接的组合上计算SHA-256哈希值.让我们在SetHash方法中实现这一点:

func (b *Block) SetHash() {timestamp := []byte(strconv.FormatInt(b.Timestamp, 10))header := 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
}

这就是整个区块!

区块链

现在让我们实现一个区块链. 从本质上讲, 区块链只是一个具有一定结构的数据库: 它是一个有序的反向链表. 这意味着数据块是按插入顺序存储的, 并且每个数据块都链接到前一个数据块.这种结构允许快速获取链中的最新区块, 并(有效地)通过其散列值获取区块.
在Golang中, 这种结构可以通过使用数组和字典来实现.数组保持有序地哈希值(在Go中数组是有序的), 而字典将保持哈希值->区块对(字典是无序的). 但是对于我们的区块链原型, 我们将只使用一个数组, 因为我们现在不需要通过它们的哈希值来获取区块.

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)
}

就是这样了吗?
要添加一个新区块, 我们需要一个现有的区块, 但是我们的区块链中没有区块!因此, 在任何区块链中, 必须至少有一个区块, 而这样的区块, 即链的第一个区块, 被称为创世区块(gensis 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()}
}

输出结果

Prev. hash:
Data: Genesis Block
Hash: fc5e6a0666636c732f11b6d159081d0838ad126026ffef5d98b9a0a8cbf2f21ePrev. hash: fc5e6a0666636c732f11b6d159081d0838ad126026ffef5d98b9a0a8cbf2f21e
Data: Send 1 BTC to Ivan
Hash: 4028898ea2a9907266de11ad1a770fb78163c05bb7b7a3d712ee59ea1473253ePrev. hash: 4028898ea2a9907266de11ad1a770fb78163c05bb7b7a3d712ee59ea1473253e
Data: Send 2 more BTC to Ivan
Hash: 5571f6b8ad167ad209b1effe129dc139934d7487999am85bf081e83116c12a5

就是这样!

总结

我们构建了一个简易的区块链原型: 它只是一个区块数组, 每个区块都于前一个区块有链接.然而, 实际的区块链要复杂的多.在我们的区块链中添加新区块是简单而快速的, 但在真正的区块链中添加新区块需要一些工作: 在获得添加新区块的许可之前, 必须执行一些繁重的计算任务(这种机制成为工作量证明).此外, 区块链是一个分布式数据库, 没有单一的决策者.因此, 一个新的区块必须得到网络中其他参与者的确认和批准(这种机制成为共识consensus).我们的区块链中还没有事务.
在以后的文章中, 我们将介绍这些特性.

Links:

Full source codes: https://github.com/Jeiwan/blockchain_go/tree/part_1
Block hashing algorithm: https://en.bitcoin.it/wiki/Block_hashing_algorithm


http://www.ppmy.cn/news/77201.html

相关文章

【六袆 - Redis】Redis内存数据库;redis数据结构;redis文档

Redis 关于redis 官方文档: https://redis.io/docs/about/数据结构文档 https://redis.com/redis-enterprise/data-structures/命令行文档 https://redis.io/commands/keys/ 关于redis Redis: 是一个开源(BSD 许可)内存数据结构存储&#xf…

Day03 02-MySQL多表查询详解

文章目录 第八章 多表查询8.1 多表查询介绍8.1.1 什么是多表查询8.1.2 多表查询基本写法8.1.3 笛卡尔积8.1.4 连接查询条件限制 8.2 连接查询分类8.2.1 内连接8.2.2 外连接8.2.3 全连接8.2.4 自然连接 8.3 子查询8.3.1 子查询简介8.3.2 在where子句中8.3.3 在from子句中8.3.4 在…

2020下半年

2020下半年 d a b 小阶向大阶对齐 b b 平均cpi: MIPS: d c 公加验,私解签 加密防止被动攻击,认证防止主动攻击 a 访问控制包括:授权,确定存取权限,实施存取权限 c a c a 先申请先得 b b 著作权包括&…

GitHub Copilot:神一样的代码助手

我肝肯定,很多很多小伙伴还不了解 Copilot 是什么,尤其是初学计算机的小伙伴,我这里普及一下吧! GitHub Copilot 是一个基于 AI 的代码自动完成工具,由 GitHub 和 OpenAI 共同开发。 GitHub 和 OpenAI 想必大家都很清楚…

【论文阅读】23_SIGIR_Disentangled Contrastive Collaborative Filtering(分离对比协同过滤)

【论文阅读】23_SIGIR_Disentangled Contrastive Collaborative Filtering(分离对比协同过滤) 文章目录 【论文阅读】23_SIGIR_Disentangled Contrastive Collaborative Filtering(分离对比协同过滤)1. 来源2. 介绍3. 模型方法3.1…

联想集团财报:收入持续下滑,联想集团财务前景已恶化

来源:猛兽财经 作者:猛兽财经 联想集团2023财年第三季度财务业绩回顾 联想集团(00992)于2023年2月16日盘后公布了该公司2023财年第三季度的财报。 财报显示,联想集团的收入已经从2022财年第三季度的201.27亿美元下降到…

路径规划 | 图解快速随机扩展树RRT算法(附ROS C++/Python/Matlab仿真)

目录 0 专栏介绍1 什么是RRT算法?2 图解RRT算法原理3 算法仿真与实现3.1 ROS C++实现3.2 Python实现3.3 Matlab实现0 专栏介绍 🔥附C++/Python/Matlab全套代码🔥课程设计、毕业设计、创新竞赛必备!详细介绍全局规划(图搜索、采样法、智能算法等);局部规划(DWA、APF等);…

python解析html数据,获取到的链接是以/或 ./ 或 ../ 开头的相对链接,不是以http开头的,需要补全

一、实现的目标 在使用爬虫获取网页html数据时,解析到的链接是/或./ 开头的相对链接,不是以http开头的链接,如:/picture/0/cca65350643c441e80d390ded3975db0.png 。此时需要完成对该链接的补全,以得到正确的链接。此外,我们需要将解析到的html数据保存到起来,将来需要展…