用Go语言实现基础区块链模型,通过定义区块结构体、哈希函数及链式连接,展示区块、哈希值及前后区块引用关系,清晰阐释区块链核心原理,帮助理解其不可篡改特性。
用Go实现简单区块链示例
作者:技术拾光
时间:2026-07-24
浏览:524
文章目录
互联网出现以来,区块链常被视为一项影响深远的底层技术。尽管许多人提到区块链就会联想到加密货币炒作,但它的实际应用远不止于此。币圈只是区块链生态的一部分,许多真实落地的项目背后,往往由企业或组织推动。
随着区块链技术持续演进,理解其基础原理与运行机制,对技术从业者而言愈发重要。从入门实现的角度看,搭建一个最简单的区块链模型,其实并没有想象中那么复杂。
本文将使用2026年较为热门的编程语言之一Go(又称Golang),演示如何手写一个基础版区块链,并帮助你理解区块、哈希与链式连接等核心概念。
随着区块链技术持续演进,理解其基础原理与运行机制,对技术从业者而言愈发重要。从入门实现的角度看,搭建一个最简单的区块链模型,其实并没有想象中那么复杂。
本文将使用2026年较为热门的编程语言之一Go(又称Golang),演示如何手写一个基础版区块链,并帮助你理解区块、哈希与链式连接等核心概念。
先搞懂区块链的基本结构
从名称上就能看出,区块链的本质是“区块”按顺序连接成“链”。每个区块中存储着数据,而区块之间通过哈希值串联起来。哈希可以简单理解为:将任意长度的输入数据,通过算法计算出一个固定长度的加密输出。由于每个区块都保存了前一个区块的哈希值,一旦某个区块的内容被篡改,后面所有区块的关联关系就会断裂,整条链也就失去可信性。 在区块链中,每个区块都可以存放数据。最简单的做法,就是将交易记录直接放入区块。比特币正是这样做的,因此你可以在链上一直向前追溯每一笔交易的历史。 假如我们只用三个区块来搭建一条最简单的链,那么第一个区块就是“创世块”。由于它前面没有其他区块,“前一个哈希”字段是空的。不过没关系,我们仍然可以将时间戳和初始交易数据作为输入,通过哈希算法计算出创世块自身的哈希值。 接下来,在第二个区块中,我们将创世块的哈希值填入“前一个哈希”字段,这一步就完成了区块之间的连接。然后,再将时间戳、交易列表和前一个哈希值一起输入哈希算法,得到第二个区块的哈希值。 后续每个区块都重复这个过程。理论上,这条链可以无限延伸。现实中,限制链条长度的通常是区块的有效性验证机制和存储能力——例如比特币的区块链体积已经非常庞大。用Go写一个简单的区块链
实现区块链的第一步,就是先定义“区块”这一数据结构。Go语言支持自定义类型,因此我们可以用结构体(struct)来描述一个区块。该结构体包含四个字段,正好对应上述核心元素。type Block struct {
timestamp time.Time
transactions []string
prevHash []byte
Hash []byte
}
定义完区块后,下一步是编写一个创建新区块的函数。该函数接收两个参数:一个字符串数组,用于存放交易记录;一个字节数组,表示前一个区块的哈希值。函数内部还会调用稍后实现的NewHash()方法,生成当前区块的哈希。
func NewBlock(transactions []string, prevHash []byte) *Block {
currentTime := time.Now()
return &Block {
timestamp: currentTime,
transactions: transactions,
prevHash: prevHash,
Hash: NewHash(currentTime, transactions, prevHash),
}
}
NewHash()函数的作用,就是将时间、交易列表和前一个哈希作为输入,最终计算出当前区块对应的哈希值。具体实现时,先将这些输入内容拼接成一个统一的字节数组input。
这里通过append()方法,将prevHash和时间字符串依次写入input。然后遍历transactions,将每条交易也追加到input中。代码中的string(rune(transaction))...这种写法,是Go语言中数据转换并追加的常见用法。
func NewHash(time time.Time, transactions []string, prevHash []byte) []byte {
input := append(prevHash, time.String()...)
for transaction := range transactions {
input = append(input, string(rune(transaction))...)
}
hash := sha256.Sum256(input)
return hash[:]
}
最后,通过crypto包中的sha256.Sum256()对input进行哈希运算,得到新的哈希值。返回结果时,使用hash[:]这种切片写法,以确保返回的是字节数组格式。
至此,构建一个能连接起来的最小化区块链模型所需的核心逻辑已经完成。为了让结果更直观,我们还可以添加几个辅助函数,在程序运行时打印区块信息。
func printBlockInformation(block *Block) {
fmt.Printf("ttime: %s\n", block.timestamp.String())
fmt.Printf("tprevHash: %x\n", block.prevHash)
fmt.Printf("tHash: %x\n", block.Hash)
printTransactions(block)
}
func printTransactions(block *Block) {
fmt.Println("tTransactions:")
for i, transaction := range block.transactions {
fmt.Printf("\t%v: %q\n", i, transaction)
}
}
接下来,只需创建交易数据、生成区块并计算哈希即可。这部分工作可以放在主函数中。需要注意的是,生成第一个区块(创世块)时,传入的是一个空字节数组,因为它没有前置区块。
func main() {
genesisTransactions := []string{"小明给小红转了50个比特币", "小红给小刚转了30个比特币"}
genesisBlock := NewBlock(genesisTransactions, []byte{})
fmt.Println("--- 第一个区块 ---")
printBlockInformation(genesisBlock)
block2Transactions := []string{"小李给小明转了30个比特币"}
block2 := NewBlock(block2Transactions, genesisBlock.Hash)
fmt.Println("--- 第二个区块 ---")
printBlockInformation(block2)
block3Transactions := []string{"小刚给小明转了45个比特币", "小明给小红转了10个比特币"}
block3 := NewBlock(block3Transactions, block2.Hash)
fmt.Println("--- 第三个区块 ---")
printBlockInformation(block3)
}
每次创建新区块时,只要将上一个区块的哈希值和当前对应的交易记录一起传给NewBlock(),新的链式关系就建立起来了。
将这部分代码汇总到一起,完整的程序如下:
package main
import (
"crypto/sha256"
"fmt"
"time"
)
type Block struct {
timestamp time.Time
transactions []string
prevHash []byte
Hash []byte
}
func main() {
genesisTransactions := []string{"小明给小红转了50个比特币", "小红给小刚转了30个比特币"}
genesisBlock := NewBlock(genesisTransactions, []byte{})
fmt.Println("--- 第一个区块 ---")
printBlockInformation(genesisBlock)
block2Transactions := []string{"小李给小明转了30个比特币"}
block2 := NewBlock(block2Transactions, genesisBlock.Hash)
fmt.Println("--- 第二个区块 ---")
printBlockInformation(block2)
block3Transactions := []string{"小刚给小明转了45个比特币", "小明给小红转了10个比特币"}
block3 := NewBlock(block3Transactions, block2.Hash)
fmt.Println("--- 第三个区块 ---")
printBlockInformation(block3)
}
func NewBlock(transactions []string, prevHash []byte) *Block {
currentTime := time.Now()
return &Block {
timestamp: currentTime,
transactions: transactions,
prevHash: prevHash,
Hash: NewHash(currentTime, transactions, prevHash),
}
}
func NewHash(time time.Time, transactions []string, prevHash []byte) []byte {
input := append(prevHash, time.String()...)
for transaction := range transactions {
input = append(input, string(rune(transaction))...)
}
hash := sha256.Sum256(input)
return hash[:]
}
func printBlockInformation(block *Block) {
fmt.Printf("ttime: %s\n", block.timestamp.String())
fmt.Printf("tprevHash: %x\n", block.prevHash)
fmt.Printf("tHash: %x\n", block.Hash)
printTransactions(block)
}
func printTransactions(block *Block) {
fmt.Println("tTransactions:")
for i, transaction := range block.transactions {
fmt.Printf("\t%v: %q\n", i, transaction)
}
}
如果运行这段程序,你会看到类似下面的输出:
$ go run example.go --- 第一个区块 --- time: 2026-04-05 15:12:18.813294 -0600 MDT m=+0.000074939 prevHash: Hash: 43ec51c50d2b9565f221155a29d8b72307247b08eaf6731cca Transactions: 0: "小明给小红转了50个比特币" 1: "小红给小刚转了30个比特币" --- 第二个区块 --- time: 2026-04-05 15:12:18.813477 -0600 MDT m=+0.000257244 prevHash: 43ec51c50d2b9565f221155a29d8b72307247b08eaf6731cca Hash: fcce5323a35cb67b45fe75866582db00fd32baeb92aac448c7 Transactions: 0: "小李给小明转了30个比特币" --- 第三个区块 --- time: 2026-04-05 15:12:18.813488 -0600 MDT m=+0.000269168 prevHash: fcce5323a35cb67b45fe75866582db00fd32baeb92aac448c7 Hash: fc1d3eee286970d85812b47c3a5bf016ae8c1de4f86b8ace972ffa Transactions: 0: "小刚给小明转了45个比特币" 1: "小明给小红转了10个比特币"整体来看,这个例子仍然比较基础,更像一个演示性质的小项目,但它已经清晰地展示了如何用Go搭建最简单的区块链结构。对于理解区块、哈希生成和链式引用这几个核心概念来说,这是一个直接且实用的入门示例。另外需要提醒一句:本文内容仅供学习参考,不构成任何投资建议、交易建议或收益承诺。加密货币和迷因币价格波动极大,实际市场数据请以官方公告、交易所页面及实时行情平台为准,投资者应独立判断、谨慎决策。
实用工具推荐
电子包浆
使用 ›绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
图片压缩
使用 ›选择画质和输出格式,预览压缩前后的大小。
相关文章