因为md5不安全、易碰撞,而sha256抗碰撞性强且被比特币采用;prevhash实现链式结构;序列化顺序影响哈希一致性;验证需逐块比对hash与prevhash;slice保障顺序不可变;时间戳需纳秒级防冲突。

为什么用 sha256 而不是 md5 计算区块哈希
因为 md5 已被证明不安全,碰撞容易构造,而区块链要求哈希不可逆且抗碰撞性强。sha256 是比特币实际采用的算法,Go 标准库 crypto/sha256 开箱即用、性能稳定。别图省事用 md5——哪怕只是练手,也建议从 sha256 开始,否则后续加难度(比如 PoW)时会踩验证不一致的坑。
Block 结构体里为什么要包含 PrevHash 字段
这是实现“链式”结构的关键。每个新区块必须显式引用前一个区块的哈希值,才能形成不可篡改的指针链。如果漏掉 PrevHash 或初始化为零值,就退化成普通列表,失去区块链的核心特性。
- 生成创世块时,
PrevHash应设为空字符串或 32 字节零值(make([]byte, 32)),不能留空或忽略 - 计算当前块哈希前,必须先序列化
PrevHash+Data+Timestamp,顺序错一点(比如把Timestamp放最前)会导致哈希不匹配 - Go 中 struct 字段顺序影响
json.Marshal结果,若用 JSON 序列化参与哈希,务必统一字段顺序和 tag(如json:"prev_hash")
如何验证一条链是否被篡改
验证逻辑很简单:遍历所有区块,检查每个 Block.Hash 是否等于它自己内容重新计算出的哈希,并且该哈希是否等于下一个区块的 PrevHash。注意边界条件:
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
- 空链或单块链无需校验
PrevHash(创世块没有前驱) - 比较哈希时用
bytes.Equal,不要用==比较切片(Go 中切片 == 只比指针) - 如果某块
Data被手动改过,它的Hash不会自动更新——你得重新调用CalculateHash()再比对
示例验证片段:
for i := 1; i <h3>为什么不用 <code>map</code> 存区块而坚持用 <code>[]*Block</code> </h3> <p>因为区块链强调顺序与不可变性。用 slice 能天然保留插入顺序、支持索引访问(比如查第 5 块)、方便做线性验证;而 <code>map</code> 无序、键需额外维护、遍历时顺序不确定——这直接破坏“链”的语义。</p>
- 即使只存 100 块,也不要用
map[uint64]*Block模拟高度索引,除非你明确需要 O(1) 随机查高,且愿意承担同步成本 - 如果真要加速查询,可在 slice 外包一层结构体,提供
GetByHeight(n int)方法,内部仍用 slice 存储 - Go 的 slice 扩容策略(翻倍)对几千块以内性能完全够用,别过早优化
链越长,越容易忽略时间戳精度问题:time.Now().Unix() 秒级精度在本地测试可能撞时间,建议用 time.Now().UnixNano() 或至少加上随机偏移,否则两个块可能生成相同哈希(尤其测试快速连续挖块时)。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










