用Python从零写一个区块链:核心原理与代码实践
1. 项目拆解一个区块链到底需要什么先说说我为什么想写一个自己的区块链。很多人觉得区块链是那种高不可攀的底层技术一上来就去看白皮书、啃共识算法结果被各种术语劝退。但如果你愿意静下心用自己最熟悉的语言——比如Python——把它从零撸一遍你会发现它离你没有那么远。区块链的本质说白了就是“一个由多个带时间戳的数据块串成的链表且这个链在物理上很难被篡改”。1.1 为什么选择Python来实现选Python不是因为它性能最快恰恰相反它很可能是我能想到的跑得最慢的方案之一。但它有一个无法替代的优势可读性极强极其适合用来表达设计意图。写一次能给别人讲清楚“哦原来这个字段是这么用的”“哦原来哈希在这里起着这个作用”。在这个项目里Python的几个特性让我省了很多力气类机制简单直接几秒钟就能把一个区块的数据结构设计出来字典、列表这些内置容器天然就和JSON兼容。后面你还会看到用标准库就能完成哈希计算和序列化不需要额外装任何第三方库。1.2 区块链的核心构成区块、链与挖矿如果让你给路人解释区块链是什么你可以这样讲一个账本每隔一段时间就会生成一页新的账页这个账页上记录了这段时间里所有的交易。账页和账页之间用“盖章”的方式串联起来这个章是数学上的印章叫哈希值。任何人想改其中一页的内容后面的所有章全部对不上马上就会露馅。对应到代码层面就是三样东西区块存储数据的最小单元包含索引、时间戳、交易记录、前一个区块的哈希值、自己的哈希值。区块链一个有序的列表节点不断往尾部追加新区块。工作量证明PoW让节点在生成区块时必须做一道有一定难度的数学题从而在机制上限制“造块”的速度和恶意篡改。注意这里有一个很多新手第一次写时会忽略的细节——区块里存的“前一个区块哈希值”是整个链表安全性的灵魂。没有它链就只是一堆普通的数据盒子而已。2. 动手之前先搞定两个关键的基础知识在真正敲代码之前有一件事值得先搞清楚哈希到底是什么以及为什么它能被当作“嫌疑指纹”来使用。如果你对哈希函数非常熟了可以跳过这一节直接去看代码。2.1 哈希函数的基本原理哈希函数从一个任意长度的输入变成一个固定长度的输出。同样的一句话哪怕只改一个字母输出的哈希值也会面目全非。并且这个输出是单向的你很难通过哈希值反推原始输入是什么。在区块链里我们用到的算法是SHA-256它的输出永远是一个64位的十六进制字符串。Python的hashlib库里自带了它不需要安装额外依赖。import hashlib print(hashlib.sha256(hello.encode()).hexdigest()) print(hashlib.sha256(hellp.encode()).hexdigest())输出两行完全不同的字符串。这就是哈希函数的一个最直观印象敏感性极高且很难伪造。有了这个工具区块身份的确认就变得非常容易谁的区块数据是什么计算出它的哈希值一比对就清楚了。如果我们把“内容哈希”再加进新区块里就可以让整个链表前后绑定在一起篡改任何一个旧区块都会改变它后面的所有哈希链条。2.2 工作量证明到底在证明什么工作量证明这个概念经常被误解。它并不是“利用电脑空转代码消耗电源”而是通过求解一个有一定难度的哈希问题证明这台电脑确实投入了一定的计算资源。说的更直白一点挖矿的过程就是不断往区块里添加一个随机数我们管它叫nonce然后计算整个区块内容的哈希值看这个哈希值是否满足一个特定条件——比如前4位全部为0。不满足就换下一个随机数继续算直到碰运气找到合适的那个数字为止。你写的这个程序越简单计算越快就越能让你直观感受到为了让哈希值满足条件你需要尝试多少个nonce。这种体验会带来一个很深刻的觉悟——真实的比特币网络之所以如此难以攻击不是代码有多神奇而是所有人都得花掉大量的算力才能产出一个区块。想伪造一批交易就等同于把整条链从头用算力重写一遍。3. 从零写代码区块类与区块链类现在正式进入代码环节。下面这段代码我用的是Python 3.8以上版本所有实现都只用标准库。3.1 定义区块的数据结构先定义一个区块类它要包含以下字段索引、时间戳、数据这个项目里我们用交易列表充当、前一个哈希、自身的哈希、以及挖矿用的随机数。import hashlib import json from time import time class Block: def __init__(self, index, timestamp, transactions, prev_hash, nonce0): self.index index self.timestamp timestamp self.transactions transactions self.prev_hash prev_hash self.nonce nonce self.hash self.compute_hash() def compute_hash(self): block_dict { index: self.index, timestamp: self.timestamp, transactions: self.transactions, prev_hash: self.prev_hash, nonce: self.nonce } block_string json.dumps(block_dict, sort_keysTrue).encode() return hashlib.sha256(block_string).hexdigest()我特意把block_dict按字段名拼出来并做JSON序列化而不是直接对self.__dict__操作是因为json.dumps对内容顺序敏感而sort_keysTrue可以保证同一个区块不管在哪台机器上计算输出都是相同的字符串。这点在分布式场景非常重要——不同机器如果字段顺序不一致得出的哈希就会不一样链就分叉了。3.2 设计区块链创世区块与连接逻辑接下来是区块链的主类。它负责维护整条链并暴露两个核心方法构建创世区块、获取最新区块并追加新区块。class Blockchain: def __init__(self): self.chain [] self.pending_transactions [] self.create_genesis_block() def create_genesis_block(self): genesis_block Block(0, time(), [], 0 * 64) genesis_block.hash genesis_block.compute_hash() self.chain.append(genesis_block) property def last_block(self): return self.chain[-1] def add_block(self, block, proofNone): self.chain.append(block)创世区块的prev_hash设置成64个0这是业内的惯例——它没有真正的上一个本体只是人为规定了一个起点。你可能会问那创世区块的数据可以随便改吗答案是不可以因为整条链的权威性都建立在“所有人都从同一个创世区块开始校验”的基础上。3.3 实现一个简单的挖矿函数工作量证明的核心函数可以这样写。它接收一个区块然后不断尝试不同的nonce值直到计算出的哈希满足难度条件。DIFFICULTY 4 def proof_of_work(block): block.nonce 0 computed block.compute_hash() while not computed.startswith(0 * DIFFICULTY): block.nonce 1 computed block.compute_hash() return computed这段代码的逻辑非常朴素把难度系数设为4代表要求哈希值以4个0开头。整个过程就是穷举没有捷径。我跑单机程序时难度4大概要试几千到几万次随机数时间在零点几秒到几秒之间浮动。注意难度系数真的不要太贪心。我之前试过一次把DIFFICULTY设成6结果非得跑几十万次不可白白等了十来分钟。合理设置是在演示环境里4是黄金参数要是你想加快演示速度降到3也可以真实场景里可以结合预估的算力动态调整目标值。4. 完整操作流程录入交易、生成区块、校验链光有区块和链的骨架还不够一个区块链系统还得有两个能力把交易写进“待打包区”、验证整条链的一致性。4.1 设计交易与新区块生成流程我们需要在Blockchain类里增加两个方法一个是new_transaction把一笔交易记录到待处理列表另一个是mine将待处理交易打包成一个新区块并把这个块链接到主链上。def new_transaction(self, sender, recipient, amount): self.pending_transactions.append({ sender: sender, recipient: recipient, amount: amount }) def mine(self): if not self.pending_transactions: return False last_block self.last_block new_block Block( indexlast_block.index 1, timestamptime(), transactionsself.pending_transactions, prev_hashlast_block.hash ) new_block.hash proof_of_work(new_block) self.chain.append(new_block) self.pending_transactions [] return new_block这里值得说说pending_transactions清空的位置。我把它放在“成功挖出区块并执行追加”之后而不是proof_of_work之前。因为如果挖矿失败或者中途抛出异常待处理交易还能保留下来重试不会白白弄丢数据。这个顺序问题我踩过一次坑有一版代码在挖矿前就清空了列表后面没能成功打包结果那条交易彻底不见了。4.2 验证整条链是否合法校验函数要同时检查两件事第一每个区块的哈希值是否和区块内容匹配第二区块之间是否通过prev_hash顺利衔接。缺一不可。def is_valid_chain(self): for i in range(1, len(self.chain)): current self.chain[i] previous self.chain[i - 1] if current.hash ! current.compute_hash(): return False if current.prev_hash ! previous.hash: return False return True这段代码每次重新计算每个块的哈希并与块内存储的哈希做比对同时检查前向链接。任何人如果想修改链上某个区块里的交易金额哪怕只改一个小数点重新计算的哈希值就会对所有后续块“失效”这个链条就会立刻被判定为非法。4.3 本地跑通一个最小演示实例把上面的代码凑齐后我们可以跑一个最简体验流程if __name__ __main__: bc Blockchain() bc.new_transaction(Alice, Bob, 1.5) bc.new_transaction(Bob, Charlie, 0.5) block1 bc.mine() print(区块1哈希, block1.hash) bc.new_transaction(Charlie, Alice, 0.2) block2 bc.mine() print(区块2哈希, block2.hash) print(链是否合法, bc.is_valid_chain())运行之后你会看到两个区块被先后生成验证返回True。这个最小的“账本”已经具备记账、打包、校验的完整闭环虽然简陋五脏俱全。5. 常见问题与排查技巧实录写完这套最小实现还不够实际动手时肯定会撞上不少坑。我把自己遇到过的和我们团队里新手常问的问题整理出来了。5.1 哈希值稳定但系统重启后无法验证这个坑非常隐蔽。如果你把区块链数据直接存成Python对象进程重启后内存里的对象自然全没了。你以为没事只要重新执行一遍创建流程就行——但问题是要保证创世区块的哈希一致性一旦创世区块里用了和之前不同的时间戳整条链就是从新的起点开始旧链数据全部无法对上了。解决办法也很简单要么把所有区块序列化到本地文件里重启后加载并逐块重算哈希校验要么设计一个程序外的约定比如创世区块的时间戳固定为某个特定常量让任何人都能重建出相同的起始状态。在这套教学代码里我建议使用后者它更简单也更容易演示。5.2 挖矿耗时过长或过短耗时的背后是DIFFICULTY这个参数在起作用。调大它会指数级增加计算量调小了又容易被瞬间造出区块。在实际项目里更强的网络算力会要求你动态调整难度而在教学环境里你只要掌握一个小技巧先设一个很小的难度值确认整个流程通顺再逐步加大感受一下指数增长的曲线。我印象最深的一次体验是把难度从3调到4耗时直接翻了七八倍——这个直观感受远比看文字描述强烈。5.3 交易列表被篡改但链检查却显示正常这种情况只会发生在校验代码有缺陷的时候。某个版本的is_valid_chain只检查了prev_hash连续没有重新计算每个区块的内部哈希于是有人改了交易内容以后链两侧的哈希结对不上但校验函数却视而不见。修复方式就是确保校验函数里每次都调用compute_hash()而不是直接拿存储的hash字段出来比对这个代码我在上面已经给出请务必照着写。5.4 常见报错速查表现象可能的原因排查方法哈希值全为None忘记在创建区块后调用compute_hash并赋值构造方法里补齐self.hash self.compute_hash()交易打包了但查不到清空pending_transactions过早确认待处理列表在成功追加到链后再清空链验证返回False时间戳不一致或字段拼接顺序错乱用json.dumps(... , sort_keysTrue)固定序列化挖矿永远死循环DIFFICULTY设得过大调小难度或增加一个最大迭代次数保护5.5 一个容易忽略但很关键的调试建议强烈建议你在proof_of_work循环里加一个打印进度的控制开关比如每1000次尝试输出一次当前nonce和计算出的哈希前缀。这个小细节看起来不起眼但当你面对一个长时间跑不出结果的程序时你会非常需要它来区分情况——到底是代码死循环了还只是纯粹运气差、还没撞到满足条件的nonce。6. 更进一步还能往这个项目里加什么一个“最简单”的区块链它的价值其实不在于代码有多高深而在于它是你理解更复杂系统的出发点。顺着这条路往下探索还有好几个值得玩的方向。6.1 增加交易签名认证现在的交易是明文并且没有身份的任何人可以伪造任意sender的转账记录。真实系统要解决的第一个问题就是身份与授权。你可以在new_transaction收到请求之后要求使用发送方的私钥对交易内容做一次签名再用公钥验签验不过就拒绝打包。这套东西用标准的加密库就能做。6.2 增加Ethereum式的智能合约执行器区块里的transactions字段目前只是普通字典但如果里面存的可执行代码链就从“账本”变成了“分布式计算机”。你可以设计一个小型的指令集转移、读取、存储、条件跳转然后让每个节点按相同顺序地执行这些指令。这样实现出来的是一条最小化的“链上状态机”虽然性能惨不忍睹但对理解状态同步的机制帮助很大。6.3 引入P2P网络节点同步单机版的区块链只能叫“区块单例”称不上网络。你可以用socket或者websocket搭一个简单节点间通信协议节点A挖到一个新块广播给节点BB收到后校验合法性再追加到本地链。一旦有分叉出现再约定“取最长的链”。做到这一步你才算真正摸到分布式系统的门把手。7. 我踩过的一些真实坑与心得最后这部分说说我在从零到完整跑通的过程中印象最深的三件事。第一少即是多。最开始我也试图二三十行代码写一个像模像样的区块链出来结果发现这个系统的核心复杂度几乎全在“校验”和“前后衔接”上根本没有所谓的花哨写法。新手最容易陷入的误区是过度设计上来就把P2P、加密签名、共识机制全塞进去可一旦出问题调试起来会非常痛苦。先把单机版写稳再逐层叠加复杂性是我反复验证过最舒服的学习路径。第二打印中间值是排错的第一生产力。有一次我写出的链怎么都不合法翻来覆去检查都觉得逻辑没问题最后加了一行打印才发现compute_hash()里把transactions和prev_hash的顺序搞反了——字段顺序变了哈希输出自然变了。而当你看不清数据流时花在“猜”上的时间往往比修复代码的时间还长。第三把测试用例当成第一等公民。我在这个项目里写的最有价值的代码不是区块链本身而是一组边界用例空交易列表打包、难度阈值恰好满足边界值、长时间无新块的空闲状态。有了这些测试每一次重构才有底气和安全感才敢舒服地改动核心逻辑而不提心吊胆。这个项目到这里已经能让你亲手摸到区块链的骨骼了。下一步把它变成什么形态玩具也好、底层模块也罢都属于你自己的延伸。我个人体会是与其问“它有什么用”不如先问自己“写完这一版我懂了多少”——而在你合上编辑器的那一刻答案通常会比预想中好很多。

相关新闻

VAR模型与Stata实操:从时间序列分析到论文实证

VAR模型与Stata实操:从时间序列分析到论文实证

1. VAR模型入门:为什么论文里它如此常见最近几年,经济金融类论文里出现频率最高的计量模型,向量自回归(VAR)绝对算一个。不管是宏观政策效应评估、股价与宏观变量的动态关系,还是行业间的溢出效应&#xff…

2026/10/13 18:57:02 阅读更多 →
C++全量编译从40分钟到5分钟:ccache与sccache缓存加速实战

C++全量编译从40分钟到5分钟:ccache与sccache缓存加速实战

刚接手这个C项目的时候,最让我头疼的倒不是代码历史包袱,而是全量编译一次要等足足四十分钟。项目体量不算夸张,真实业务代码也就几百个编译单元,但牵扯到Protobuf、Boost这类重型依赖,每次clean build都像一次长途旅行…

2026/10/13 18:57:02 阅读更多 →
Python内存泄漏排查实战:引用计数、垃圾回收与gc模块用法

Python内存泄漏排查实战:引用计数、垃圾回收与gc模块用法

很多写Python的朋友都有过这种经历:线上服务跑了几天,内存占用从几百MB一路涨到几个GB,最后被运维盯上,开会点名要看排查报告。我也遇到过,而且不止一次。第一反应是加机器、重启进程,但治标不治本。直到我…

2026/10/13 18:57:02 阅读更多 →

最新新闻

Cursor额度重置教程:设备指纹清理实现合规续杯

Cursor额度重置教程:设备指纹清理实现合规续杯

简介:本资源是面向软件开发者的 Cursor 编辑器 11 月续杯实战源码包,聚焦解决免费用户模型调用受限、账号续期繁琐等实际痛点,适用于中初级开发者快速提升 AI 编程效率。压缩包共 3 个文件,含 .inscode(Cursor 插件配置…

2026/10/13 19:38:20 阅读更多 →
用Claude Code摸清老项目技术栈:三轮提示词框架与实战记录

用Claude Code摸清老项目技术栈:三轮提示词框架与实战记录

“只管去写”系列到了第二天。今天的任务很明确:用Claude分析一个老项目的技术栈。这件事听起来远没有写一个新功能那么有成就感,但只要你接过大半年之前自己写的代码、接过离职同事留下的半成品项目、或者刚入职需要快速搞清一套业务系统的底细&#xf…

2026/10/13 19:38:20 阅读更多 →
开源协作的隐形基石:高效代码评审实践指南

开源协作的隐形基石:高效代码评审实践指南

做开源项目这几年,我越来越确信一件事:代码评审(code review)是整个协作链条里最被低估的一环。很多人觉得代码写完、测试跑通、合并进去就完事了,可真正把一个项目推过几个版本之后才发现,评审才是让代码质…

2026/10/13 19:38:20 阅读更多 →
Python pickle序列化实战:从协议版本到安全红线全解析

Python pickle序列化实战:从协议版本到安全红线全解析

如果你写过 Python,一定遇到过这类需求:程序跑完把内存里的字典、列表或者某个自定义类实例保存到磁盘,下次启动再原封不动读回来。Python 为此内置了一个序列化模块叫 pickle,标题说得很直白——Pickle 是 Python 内置的序列化模…

2026/10/13 19:38:20 阅读更多 →
AnyPS5:不越狱的PS5增强方案与边界协同架构

AnyPS5:不越狱的PS5增强方案与边界协同架构

项目标题:“AnyPS5”这个名称本身带有强烈的指向性与模糊性并存的特征——它既像一个技术代号,又像一句口号;既暗示兼容性、泛用性(“Any”),又锚定在特定硬件生态(“PS5”)。但问题…

2026/10/13 19:38:20 阅读更多 →
互联网大厂薪酬结构全解析:总包、级别、绩效与谈薪技巧

互联网大厂薪酬结构全解析:总包、级别、绩效与谈薪技巧

1. 先说结论:今年这个薪酬盘子到底什么情况每年这个节点,总有人拿着某头部互联网平台的薪酬截图或者 Offer 在各个群里问“这个数正常吗”。说实话,我在这一行摸爬滚打了十几年,带过团队、做过招聘、也背过绩效,今年这…

2026/10/13 19:37:19 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →