跳到主要内容

学习与原理

本文面向零基础到入门的同学,结合本仓库的页面与代码,说明「每个路由干什么」「用了什么技术」「区块链里常见概念在本项目里如何体现」。读完你可以按图索骥打开对应页面做实验。

建议先按顶部导航跑通一遍:流程首页钱包 挖矿转账 链上浏览,再回来看原理会更直观。

写给初学者

区块链可以粗浅理解成:很多人各自保存一份结构相同、按顺序增长的「账本页」(区块),通过密码学共识规则,让大家对「哪一页才是合法的下一页」达成一致。你不需要一次弄懂所有词,本页把概念拆成和本 Demo 一一对应的几块。

本仓库是一个教学用迷你链 + Web 控制台:链逻辑跑在 Node 服务端(Next.js 的 Route Handler),你在浏览器里点点按钮,就是在调用 HTTP 接口改链的状态。它不是以太坊主网,也没有真金白银。

若你关心挖矿在算什么(类比特币的 80 字节头、Hash256、小端目标、Merkle),可直接跳读 《PoW 算法说明(类比特币·完整速查)》;与根目录 README.md 第 12 节内容一致,便于离线复习与面试口述。

路由与各页面功能

下面这张表对应顶部导航和实际文件路径,方便你对照代码。

路由主要做什么代码入口(参考)
/总览推荐操作顺序、常见问题(余额为 0、转账后没变等)。app/page.tsx
/wallet生成密钥对(演示用)、把公钥/私钥/矿工地址等存到浏览器 localStorage;用 POST /api/balance 查余额(避免超长公钥走 URL)。app/wallet/page.tsx
/mine指定矿工地址(公钥)单次1 单线程挖一块、2 多 Worker 约 100% CPU 挖一块。持续挖矿:通过下拉选算力模式(默认约 100% 多 Worker,可选 90% 或单线程)、可选最长秒数,循环取任务 → 本机 PoW → POST /api/mine 提交,可停止(当前块完成后结束)。服务端始终只校验并链接。app/mine/page.tsxapp/mine/mineClient.tsapp/mine/minePow.worker.tsapp/api/mine/work/route.tsapp/api/mine/route.ts
/transfer构造一笔已签名转账,提交后只进入交易池;要上链需再到「挖矿」完成 PoW 并提交区块。app/transfer/page.tsxapp/api/transactions/route.ts
/explorer轮询链状态:高度、难度、最新哈希、交易池列表、区块列表(可展开 JSON)。支持自动滚到最新(可关)。app/explorer/page.tsxapp/api/state/route.ts
/learn就是当前这篇「学习与原理」长文。app/learn/page.tsx

跨页面共用的「当前钱包状态」在 src/context/WalletContext.tsx,由 src/components/AppChrome.tsx 包住整站,所以换页不会丢主钱包公钥(除非清除本地存储)。

技术栈说明

框架与语言

  • Next.js 16(App Router):全栈框架。本项目的页面 app/**/page.tsxHTTP APIapp/api/**/route.ts(Route Handlers)。一次 pnpm dev 同时起前端页面和后端接口。
  • React 19:构建 UI。带交互、要用浏览器 API(如 localStorage)的组件会标 "use client"
  • TypeScript:静态类型,链核心逻辑在 src/lib/*.ts,减少低级错误。
  • Tailwind CSS v4:样式通过 @import "tailwindcss" globals.css 里的自定义类(如 .panel.learn_doc)组合。

与链相关的库

  • elliptic:椭圆曲线密码,本项目用 secp256k1(和比特币同曲线家族)做密钥生成、签名与验签。见 src/lib/wallet.ts
  • Node cryptosha256 用于交易 idTransaction.calculateId)。
  • @noble/hashes + @scure/base:区块 PoW 的 Hash256(双 SHA-256)与 hex 编解码在 src/lib/powBytes.ts(浏览器与 Node 共用算法;服务端 src/lib/pow.ts / sha256d.ts 委托同一套字节逻辑)。Merkle 与确定性序列化仍见 src/lib/merkle.tssrc/lib/hash.ts
  • ws:可选的 P2P WebSocket 服务,在 src/instrumentation.ts 里于 Node 进程启动时挂上。见 src/lib/p2pServer.ts

工程与包管理

  • pnpm:推荐包管理器;package.json 里有 packageManager 字段;根目录 .npmrc 允许 Next 依赖(如 sharp)执行安装脚本。
  • Jest + ts-jest:单元测试链逻辑,见 __tests__/blockchain.test.ts
  • ESLinteslint.config.mjs(flat config)+ eslint-config-next

区块链在解决什么问题(直觉版)

想象多人要共用一本账,又不能完全信任某一台中心服务器:

  • 每一笔变动要有凭证(密码学签名),别人能验证是不是本人授权。
  • 账页的先后顺序要明确,且难以被单方面篡改(后面区块会「挂」在前面区块的哈希上,一改全链对不上)。
  • 谁来决定「下一页写什么」要有规则——本 Demo 用极简的 工作量证明(PoW):谁先算出符合难度的哈希,谁就有权提议下一个区块(并拿奖励)。

真实公链还有更复杂的共识、经济模型、状态存储等;本仓库只保留最小可运行骨架,方便你把「区块—交易—挖矿—同步」跑通。

本项目里的「链」长什么样

在代码里,链就是一个区块数组,从创世块(高度/索引 0)开始,一块接一块。类 Blockchainsrc/lib/blockchain.ts)维护:

  • chain:已确认的区块列表。
  • transactionPool:已广播/提交、但尚未写入任何区块的交易。
  • difficulty:当前 PoW 难度(参与目标值 T = (2^256-1) >> difficulty,越大越难挖),会按出块间隔在上下限内调整。详见 《PoW 算法说明》

界面上的高度在 API 里用的是 chain.length(包含创世块)。所以只存在创世块时高度为 1;再挖一块高度为 2,以此类推。

区块结构、哈希与工作量证明

每个区块大致包含:索引上一块哈希时间戳本块包含的数据(交易列表 + 奖励交易)、本块哈希难度nonce

块哈希(展示值):由80 字节区块头Hash256(双 SHA-256)得到 32 字节,再整体反序后转十六进制,即你在浏览器里看到的「块哈希」。它与「头里存的父哈希字节序」不是同一视角,下面会说明。

PoW:对区块头做 Hash256 得到 work,将 work 视为小端无符号 256 位整数,必须严格小于目标值 T = (2^256-1) >> difficulty;通过递增 32 位 nonce(溢出绕回)试错。data 先算 Merkle 根再写入头。核心实现见 src/lib/powBytes.ts(浏览器挖矿与链上校验同源),服务端封装见 src/lib/pow.tssrc/lib/merkle.tssrc/lib/sha256d.ts

更系统的公式、字段表与源码索引见专节 《PoW 算法说明(类比特币·完整速查)》

链校验:新块必须满足「索引 = 上一块 +1」「父哈希对上」「区块头可复算且 Hash256 满足目标」等条件,否则拒绝。见 isValidNewBlock / isValidChain

交易、钱包与数字签名

钱包在本 Demo 里就是一对密钥:私钥保密,公钥公开当作「地址」。转账时用私钥对交易内容派生出的 id做签名,链上节点用公钥验证——伪造签名在计算上不可行(在正确实现前提下)。

出块奖励交易没有 fromAddress(视为币基/系统铸币),不需要签名;普通转账必须有 fromAddress + 签名。见 src/lib/transaction.ts

安全提醒(必读):本教程在网页里明文传私钥只是为了演示验签流程。真实 DApp 应使用钱包扩展(如 MetaMask)在本地签名,绝不要把主网私钥贴进网页

余额是怎么算出来的

本项目没有 UTXO 模型,而是扫整条链:对每个区块里的每笔交易,若 toAddress 等于你的公钥就加金额,若 fromAddress 等于你的公钥就减金额。见 Blockchain.getBalance

因此:

  • 挖矿奖励打给矿工公钥 → 该公钥余额增加(默认每次奖励 MINE_REWARD,常为 50)。
  • 多挖几次、奖励都进同一地址 → 余额累加(例如两次 ×50 = 100)。
  • 交易还在交易池里 → 不会计入余额,必须被打进区块。
  • 查余额的公钥必须和「链上记录里出现的字符串」完全一致(矿工地址填错就会查错人)。

挖矿、出块奖励与难度

每一轮开始前,服务端GET /api/mine/work 中把当前交易池快照与一笔奖励交易(发给矿工地址、时间戳与任务绑定)组成 data,连同父哈希、难度、固定时间戳等一并下发。你在浏览器里对这份快照做 PoW 找 nonce,再 POST /api/mine 提交完整 Block JSON;服务端 Blockchain.submitMinedBlock 校验通过后 addBlock 并清空交易池。持续挖矿只是在前端重复「取任务 → PoW → 提交」。若在你挖矿期间池子或链尖变了,该轮提交会失败并提示重新取任务(持续模式会因此结束循环)。

难度调整:每隔若干块,根据出块间隔调高或调低 difficulty(有上下限,见 POW_MIN_DIFFICULTY / POW_MAX_DIFFICULTY),目标值随 difficulty 变化。真实比特币用 compact nBits 编码目标,这里用位移推导目标,便于对照理解。

更细的逐步说明(点击按钮后发生了什么、怎样算挖成功)见下一节 《挖矿详解》

挖矿详解:含义、点击流程与成功条件

1. 「挖矿」在这里是什么意思?

日常语言里可以把它想成:用计算机做大量试错计算,直到算出一个满足规定形状的区块「指纹」(哈希),从而有权把一页新账本(新区块)接到现有链上。这种用算力换「记账权」的思路,属于工作量证明(Proof of Work, PoW)的一种极简实现。

在本仓库里,「挖矿」不是去挖比特币主网;它是在你自己的浏览器里对服务端下发的任务做 PoW,再由服务端 Blockchain.submitMinedBlock 校验通过后把块追加到 chain 并清空交易池。(创世块仍在 Node 里用 mineBlockPow 预挖一次,逻辑与浏览器一致,见 createGenesisBlock。)

2. 「挖矿」页上有哪些操作?

实现见 app/mine/page.tsx(调度)、app/mine/mineClient.ts(单线程与多 Worker 入口):

  • 单次挖矿挖矿一次(单线程)mineBlockPowU8100% 性能挖一块 走满逻辑核数的 minePow.worker.ts 分片。各只完成一轮上链。
  • 持续挖矿:页面「算力模式(下拉)」中选择模式,默认选中约 100% 逻辑 CPU(多 Worker),可改为 90% 或单线程;可选「最长运行(秒)」(不填则仅「停止持续挖矿」结束)。循环调用与单次相同的「取任务 → PoW → 提交」;某轮失败会中断循环。停止请求在当前这一块的 PoW 或提交结束后生效(无法在同步哈希循环中途强行打断)。

3. 每一轮上链,从上到下发生了什么?

无论单次还是持续里的每一圈,技术顺序如下(便于对照源码):

  1. 浏览器请求 GET /api/mine/work?minerAddress=...(见 app/mine/page.tsxapp/api/mine/work/route.ts),拿到 JSON 任务:versionpreviousBlockHashHextimestampMsdifficultydata(池内交易 + 奖励交易)、nextIndex
  2. 本机算 PoWapp/mine/mineClient.ts 调用 mineBlockPowU8(单线程)或 app/mine/minePow.worker.tsmineBlockPowShardU8(多 Web Worker 分片),在用户 CPU 上循环改 nonce,直到满足下一节的哈希条件。
  3. 组装待提交区块:用任务里的字段填入 Block 形状——index = nextIndexpreviousHash = previousBlockHashHextimestamp = timestampMsdata 原样沿用任务快照,difficulty 不变,hash/nonce 为刚算出的结果。
  4. 浏览器POST /api/mine 发 JSON:{ "minerAddress": "…", "block": { … } }(见 app/api/mine/route.ts)。
  5. 服务端 Block.fromJSON 后执行 submitMinedBlock:核对链尖与交易池是否与任务快照一致、奖励是否指向该 minerAddressverifyBlockPow 通过,再 addBlock
  6. 清空交易池:校验通过后 transactionPool = []
  7. 持久化与广播touchPersistence()broadcastLatest()(同前)。
  8. 响应浏览器:HTTP 201 返回新块 JSON;若池子或链尖已变,返回 400 与「请重新获取挖矿任务」类提示。

4. 怎样算「挖矿成功」?算的是什么?

「成功」在这里指:找到 32 位 nonce,使得Hash256(80 字节区块头)小端无符号 256 位整数意义下严格小于目标值 T。实现见 mineBlockPowU8 / hashMeetsTargetU8src/lib/powBytes.ts),服务端校验用 verifyBlockPowsrc/lib/pow.ts,内部同源)。

区块头字段(与比特币布局一致,难度以 uint32 写入头内以便与块上 difficulty 绑定):

  • version(4 字节 LE,当前为 1)
  • prevBlock(32 字节:父块「展示用块哈希」的十六进制解码后按字节反序,与比特币头内存储方式一致;创世父哈希为全 0)
  • merkleRoot(32 字节:对 data 做 Merkle 树;普通交易叶子为 Hash256(txid 字节),其它条目用稳定序列化后再 Hash256,奇数个叶子复制最后一个)
  • time(4 字节 LE,Unix ,由毫秒时间戳换算)
  • difficulty(4 字节 LE,与链上难度字段相同)
  • nonce(4 字节 LE,从 0 递增,溢出后绕回 0)

目标值T = (2^256 - 1) >> difficultytargetFromDifficulty)。difficulty 越大,T 越小,期望尝试次数指数级上升(随机模型下约每 +1 减半命中概率)。

展示的块哈希:对 Hash256 的 32 字节输出再整体反序后转十六进制(比特币区块浏览器上的块 ID 惯例),与头内参与运算的字节顺序区分开——面试时能说清这一点很重要。

循环逻辑是不断调用 computeBlockWorkHashU8(或经 computeBlockWorkHash 的 Buffer 封装)换 nonce,直到命中目标;在有限时间内几乎必然成功。若提交时链尖或交易池已与任务快照不一致,POST /api/mine 会返回错误而非 PoW「运气」问题。

5. 和你在界面上看到的现象怎么对应?

  • 单次挖矿的两个按钮各触发一轮上述流程,成功后高度 +1;矿工地址多一笔奖励(查余额请用同一公钥)。
  • 持续挖矿会在日志里出现 [第 N 块] 前缀,每成功一轮高度 +1;达到设定秒数或点停止后结束。
  • 交易池里有待打包转账时,同一次挖矿会把它们和奖励一起写进 data;因此转账后要再挖一次才会在余额上看到转账效果。
  • 难度会在每挖若干块后根据出块快慢微调(getAdjustedDifficulty),你在「链上浏览」里看到的难度数字可能随时间变化。

6. 与真实比特币等公链的差异(避免误解)

本仓库已采用Hash256 + 小端整数与目标比较 + Merkle 根 + 展示块哈希反序等核心习惯,与比特币 PoW 同一套叙事;差异主要在于:目标值由本链的 difficulty 位移推导,而未实现 compact nBits;区块头未包含 height / bits 的完整主网编码;也无主网共识与分叉选择。掌握本节后读比特币开发者文档时,可直接对照「nBits、工作量证明校验、merkleblock」等章节。

需要一页纸背下来的字段表、公式与文件对照,请继续阅读 下一节《PoW 算法说明》(与根目录 README.md 第 12 节内容同源,便于离线复习)。

PoW 算法说明(类比特币·完整速查)

本节把当前仓库里的挖矿判定写成可对照源码的规格说明,方便写进简历/面试口述;与 README.md「工作量证明(PoW)算法说明」互为补充。

1. 一句话

固定 80 字节区块头计算 work = Hash256(header) = SHA256(SHA256(header));记 H = uint256LE(work)T = (2^256-1) >> difficulty,当且仅当 H < T 时 PoW 有效。界面上的块哈希reverse(work) 的十六进制。

2. 区块头 80 字节布局(全小端)

偏移长度字段说明
04versionint32 LE,当前恒为 1
432prevBlock父块展示哈希(64 hex)解码后按字节反序写入头内;创世为 32 字节全 0x00(即 previousHash 存 64 个 0
3632merkleRoot本块 data 的 Merkle 根(见下节)
684timeUnix uint32 LE
724difficultyuint32 LE,与区块上的 difficulty 字段一致
764nonceuint32 LE,挖矿时从 0 递增,溢出绕回 0

3. Merkle 树规则

  • 交易instanceof Transaction 或 JSON 还原后带 id 的交易形对象):叶子 = Hash256(hex_decode(tx.id))
  • 其它对象(如创世 { "type": "genesis" }):叶子 = Hash256(utf8(stableStringify(obj)))
  • 自底向上两两拼接 Hash256(left ‖ right);若本层奇数个节点,复制最后一个再配对(比特币规则)。
  • 根即为头内 merkleRoot 的 32 字节。

4. 难度与调整

目标 T = targetFromDifficulty(difficulty) = (2^256-1) >> difficulty(BigInt 位移)。difficulty 越大,T 越小,期望尝试次数近似按指数增长。

每隔 DIFFICULTY_ADJUST_INTERVAL 块按出块时间与 BLOCK_GENERATION_INTERVAL 比较,难度 ±1,并夹在 POW_MIN_DIFFICULTYPOW_MAX_DIFFICULTY 之间。创世难度由 POW_GENESIS_DIFFICULTY 决定,且 isValidGenesisBlock 会校验该值。

5. 校验顺序(接块时)

  1. index === prev.index + 1previousHash === prev.hash(展示哈希字符串一致)。
  2. 用当前块的 datatimestampdifficultynonce 重算 work,确认 reverse(work).toString("hex") === block.hash
  3. 确认 uint256LE(work) < T(difficulty)

对应代码:Blockchain.isValidNewBlockverifyBlockPow

6. 源码文件索引

  • src/lib/powBytes.ts — 与链校验一致的 Uint8Array 路径:doubleSha256U8computeBlockWorkHashU8mineBlockPowU8mineBlockPowShardU8verifyBlockPowU8targetFromDifficulty 等(依赖 @noble/hashes/sha2.js@scure/base
  • src/lib/pow.ts — Node/服务端 Buffer 封装:computeBlockWorkHashmineBlockPow(创世预挖)、verifyBlockPow
  • src/lib/sha256d.tsdoubleSha256(委托 powBytes
  • src/lib/merkle.tscomputeMerkleRoot(委托 powBytes
  • src/lib/hash.tsstableStringify
  • src/lib/mineTypes.tsMineWorkResponse(与 GET /api/mine/work 对齐)
  • src/lib/blockchain.tssubmitMinedBlockgetAdjustedDifficultyisValidGenesisBlockcreateGenesisBlock
  • app/mine/mineClient.tsapp/mine/minePow.worker.ts — 浏览器侧挖矿调度与 Web Worker
  • src/lib/block.tsfromJSON 将交易还原为 Transaction,保证持久化后 Merkle 一致
  • src/lib/config.tsPOW_* 与出块参数

7. 升级与旧数据

若你曾使用旧版「单 SHA256 + 十六进制前缀 0」的链数据,升级到当前 PoW 后无法通过校验。请删除 data/chain-state.json(或改用新的 CHAIN_DATA_PATH)后重启节点。

8. 与比特币主网的差异(面试收尾句)

主网用 compact nBits 编码目标、区块头字段演进更复杂;本演示用位移目标 + 固定头布局,重在对齐 Hash256、LE 比较、Merkle、展示反序四条主线,读 BIP / 比特币开发者文档时可逐项对照「我们还简化了什么」。

交易池与「为什么要再挖一次矿」

交易池(Mempool)是「已验证通过、等待被打包」的交易集合。提交转账 API 成功,只表示进入了池子,账本(链)尚未更新

只有挖矿成功、生成新区块,这些交易才作为区块数据的一部分成为不可更改的历史(在本 Demo 里没有分叉选择,更简单)。所以流程是:提交交易 → 再挖矿 → 余额变化可在链上体现

P2P 网络在做什么

单进程 Demo 里,链存在服务端内存(并可写 JSON 文件)。若开第二个节点(如 pnpm dev:node2),两个进程各自有一份状态,通过 WebSocket 交换「最新块」「全链」「交易池」消息,尝试对齐更长的合法链。见 src/lib/p2pServer.ts

这与比特币的 P2P 协议复杂度差很远,但能帮助理解「节点之间要同步什么数据」。

数据存在哪里

  • 链状态:默认写入项目下 data/chain-state.json(可通过 CHAIN_DATA_PATHCHAIN_PERSIST 配置)。重启 Node 可恢复。
  • 浏览器里的钱包草稿localStorage,仅本机、本域名,与链上账户体系无关。

后端 API 一览

与页面按钮对应的主要接口(详见仓库根目录 README.md 的表格与 curl 示例):

  • GET /api/state:给浏览器聚合状态;加 ?includeBlocks=false 时不返回区块数组(链上浏览页轮询用,体积小)。
  • POST /api/wallets:生成密钥对。
  • POST /api/balance:推荐;body 为 JSON,例如 { "address": "你的公钥hex" }
  • POST /api/transactions:提交签名交易。
  • GET /api/mine/work?minerAddress=...:下发当前挖矿任务(交易池快照 + 奖励交易 + 难度与时间戳)。持续挖矿时每一轮都会重新请求。
  • POST /api/mine:body 为 { "minerAddress", "block" },提交客户端已算好 PoW 的完整区块 JSON,服务端校验后上链。无单独的「持续挖矿」接口,多轮即多次调用上述两接口。

代码地图(该读哪些文件)

按「从外到内」的顺序阅读,通常最省力:

  1. 页面与交互app/**/page.tsx(挖矿相关另有 app/mine/mineClient.tsminePow.worker.ts)、src/components/SiteNav.tsxsrc/context/WalletContext.tsx(跨页钱包状态)。
  2. HTTP 入口app/api/**/route.ts。每个文件导出 GET / POST 等函数,即 REST 端点。
  3. 单例链与持久化src/lib/chainService.ts(内存里的唯一 Blockchain 实例)、src/lib/persistence.ts(读写 JSON)。
  4. 链核心src/lib/blockchain.tssrc/lib/block.tssrc/lib/transaction.tssrc/lib/powBytes.tssrc/lib/pow.tssrc/lib/merkle.tssrc/lib/sha256d.tssrc/lib/hash.tsstableStringify)、src/lib/config.tssrc/lib/mineTypes.ts
  5. 密码学钱包工具src/lib/wallet.ts(elliptic secp256k1)。
  6. P2Psrc/lib/p2pServer.ts、进程入口 src/instrumentation.ts
  7. 自动化测试:配置见 Jest;若有针对链逻辑的测试,可直接 new Blockchain 断言,无需经过 HTTP。

从点击按钮到链状态变化

以「挖矿」为例,一条典型路径是:

  1. 浏览器 /mine 页先 GET /api/mine/work?minerAddress=...,由 app/api/mine/work/route.ts 返回任务 JSON。
  2. 页面在本机运行 mineBlockPowU8(单线程)或 Web Worker 分片(多核),得到 hashnonce;与「挖矿」页上选的单次/持续模式一致。
  3. 再向 POST /api/mine 提交 { minerAddress, block };Next.js 交给 app/api/mine/route.ts
  4. 处理器 getBlockchain()全进程唯一链实例,执行 submitMinedBlock:校验通过后更新 chain、清空 transactionPool,并 touchPersistence()
  5. broadcastLatest() 通过 WebSocket 同步其他节点(若启用 P2P)。
  6. 接口返回 201 与新块 JSON;/explorer 轮询 /api/state 等即可看到高度与池子变化。

「转账」路径仍是:提交交易只进池子,直到某次「挖矿」成功把池内交易(与任务快照一致)写入区块。

环境变量与可调参数

在启动命令前设置环境变量即可(Windows PowerShell 示例:$env:MINE_REWARD=100; pnpm dev)。

变量作用(初学者理解)
MINE_REWARD每挖出一个块,奖励交易给矿工的数额(默认常是 50)。
DIFFICULTY_ADJUST_INTERVAL每隔多少个块检查一次出块速度,并尝试调整难度。
BLOCK_GENERATION_INTERVAL期望的出块间隔(秒),用于难度调整的参考,不是强制休眠。
P2P_PORT / PEERS / ENABLE_P2P控制是否起 WebSocket、监听端口、主动连接哪些节点。
CHAIN_PERSIST / CHAIN_DATA_PATH是否把链写入磁盘、文件路径(多节点时请用不同路径避免互抢)。
POW_GENESIS_DIFFICULTY创世块 PoW 难度(参与 T = (2^256-1) >> difficulty)。改动后须清空旧链数据,见 PoW 算法说明 §7
POW_MIN_DIFFICULTY / POW_MAX_DIFFICULTY自动难度调整时的上下限,防止过易或过难。

本演示与真实公链的差距

便于初学者建立正确预期,避免把 Demo 当成生产系统:

  • 无真实经济安全模型、无大量节点博弈;P2P 与共识极简。
  • 无私钥由用户硬件/钱包托管的最佳实践;验签流程为教学简化。
  • 无 UTXO、无 SPV 轻客户端的默克尔证明路径、无智能合约执行环境(本链仅在 PoW 头内使用 Merkle 根打包 data)。
  • 难度目标为教学用位移模型(非主网 nBits);奖励与调整参数与主网不可类比。

延伸学习建议

  • 阅读 Bitcoin白皮书 中与「链结构、工作量证明、时间戳」相关的章节(概念层面)。
  • 了解 以太坊账户模型UTXO 模型的对比(本 Demo 更接近简化的账户余额扫描)。
  • 学习 Next.js App Router 官方文档中的 Route Handlers、Server/Client Component 边界。
  • 在浏览器开发者工具里对 src/lib/powBytes.ts(或打包后的对应模块)下断点,跟一轮 mineBlockPowU8;或在 Node 侧跟 createGenesisBlock 里的 mineBlockPow。对照 《PoW 算法说明》 与根目录 README.md 第 12 节;改 MINE_REWARDPOW_* 观察 /explorer 与余额变化。