用 Node.js 从零构建加密货币区块链:完整开发手册

·

这是一份面向前端开发者和区块链初学者的实战笔记,仅用 Node.js 与常用模块 即可在本地跑通一套最小可用的加密货币网络,涵盖核心概念、代码范例与可落地的进阶方向。

为什么选择 Node.js 做区块链开发

关键词:区块链开发、Node.js、加密货币、去中心化、共识算法。


整体设计与运行路径

我们将从 0 到 1 创建一条演示链,包含五大核心模块:

  1. 区块结构(Block):时间戳、交易集合、前一区块哈希。
  2. 交易模型(Transaction):发送方、接收方、金额、签名。
  3. 钱包机制(Wallet):生成密钥对,校验签名。
  4. 工作量证明(PoW):动态难度调整 & 最快最长链规则。
  5. P2P 网络层(Network):节点发现、区块广播、延迟补偿。

典型场景演示:


开始动手:环境与初始化

安装 Node.js

# macOS / Linux
curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
nvm install --lts
node -v   # 输出 v20.x.x 则为成功
# Windows
# 下载 MSI 安装包后勾选 Add to PATH

👉 跟着这三步,三分钟完成 Node.js 开发机配置

初始化项目

mkdir naivechain && cd naivechain
npm init -y
npm i crypto-js level ws

目录结构建议(最小可用):

.
├── package.json
├── src/
│   ├── index.js       // 主节点
│   ├── block.js       // 区块
│   ├── transaction.js // 交易
│   ├── wallet.js      // 密钥与签名
│   ├── miner.js       // PoW 挖矿端

核心模块逐层拆解

1. Block 区块模型

// src/block.js
const crypto = require('crypto-js');

class Block {
  constructor(transactions, previousHash) {
    this.timestamp = Date.now();
    this.transactions = transactions;   // Array<Transaction>
    this.previousHash = previousHash;
    this.nonce = 0;                     // PoW 变动字段
    this.hash = this.calcHash();        // 当前区块 Id
  }

  calcHash() {
    return crypto.SHA256(
      this.timestamp +
      this.previousHash +
      JSON.stringify(this.transactions) +
      this.nonce
    ).toString();
  }

  mine(difficulty) {
    const target = Array(difficulty + 1).join('0');
    while (!this.hash.startsWith(target)) {
      this.nonce++;
      this.hash = this.calcHash();
    }
  }
}

module.exports = Block;

关键词:区块哈希、Merkle 根、工作量证明。


2. Transaction 与 Wallet

// src/transaction.js
class Transaction {
  constructor(from, to, amount, signature = null) {
    this.from = from;   // publicKey
    this.to = to;
    this.amount = amount;
    this.timestamp = Date.now();
    this.signature = signature;
  }

  getHash() {
    return crypto
      .SHA256(this.from + this.to + this.amount + this.timestamp)
      .toString();
  }

  sign(keyPair) {
    if (keyPair.getPublic('hex') !== this.from) {
      throw new Error('Invalid keyPair');
    }
    this.signature = keyPair.sign(this.getHash(), 'base64').toDER('hex');
  }

  isValid() {
    if (this.from === '0') return true;   // 奖励交易
    if (!this.signature) return false;
    return keyPair.verify(this.getHash(), this.signature, this.from);
  }
}

配套 Wallet(简化版):

// src/wallet.js
const EC = require('elliptic').ec;
const ec = new EC('secp256k1');

exports.createWallet = () => {
  const key = ec.genKeyPair();
  return {
    publicKey: key.getPublic('hex'),
    privateKey: key.getPrivate('hex'),
    keyPair: key
  };
};

关键词:数字签名、私钥、公钥验证。


3. 工作量证明(PoW)

adjustDifficulty(lastBlock, currentTime) {
  return lastBlock.timestamp + 60000 > currentTime
    ? DIFFICULTY + 1
    : Math.max(DIFFICULTY - 1, 1);
}

安全本质:算力壁垒 + 最长链原则。


4. P2P 网络同步:ws 实战

种子节点

// src/index.js
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });

let chain = [createGenesisBlock()];
let sockets = [];

wss.on('connection', (ws) => {
  sockets.push(ws);
  ws.send(JSON.stringify({ type: 'CHAIN', data: chain }));
  ws.on('message', (msg) => handleMessage(msg));
});

function handleMessage(data) {
  const msg = JSON.parse(data);
  switch (msg.type) {
    case 'CHAIN':
      chain = msg.data;
      break;
    case 'TRANSACTION':   // 收到新的交易池
      broadcast({ type: 'TRANSACTION', data: msg.data });
      break;
    case 'BLOCK':         // 收到新区块
      chain.push(msg.data);
      broadcast({ type: 'BLOCK', data: msg.data });
      break;
  }
}

function broadcast(obj) {
  sockets.forEach(s => s.send(JSON.stringify(obj)));
}

挖矿端

// src/miner.js
const WebSocket = require('ws');
const ws = new WebSocket('ws://localhost:8080');
let pendingTx = [];

ws.onmessage = (e) => handle(e.data);
ws.onopen = () => setInterval(() => mine(), 3000);

function mine() {
  const block = new Block(pendingTx, lastHash());
  block.mine(DIFFICULTY);
  ws.send(JSON.stringify({ type: 'BLOCK', data: block }));
}

👉 点击体验:本地运行两条节点实时同步区块链


5. 持久化、钱包 API、REST 接口拓展

只需在 ./src/server.js 引入 expresslevel

const express = require('express');
const level = require('level');

const db = level('./blocks');
router.get('/balance/:addr', async (req, res) => {
  // 直接遍历链上交易 UTXO 模型
});

关键词:LevelDB 持久化、RESTful API、UTXO 计算。


常见问题与解答(FAQ)

Q1:我只有前端经验,完全不懂后端加密,能做吗?
A:可以!本教程所有概念仅依赖 JavaScript 基础语法 + 几个 npm 模块。椭圆曲线、哈希函数的细节均已被封装。

Q2:Block 越长,计算 Hash 会不会越慢?
A:区块体大小挖矿难度 才是瓶颈。链长 100 与链长 10000 在单机验证时差距不到 1 ms,因为每次仅验证最后一组哈希。

Q3:PoW 太耗电,切换到 PoS 要改动什么?
A:核心在 mineBlock 步骤:不再需要 nonce+CPU 盲猜,而是按币龄/持币量选择记账节点。其余账本结构不变。

Q4:怎么防止“钱包重放”攻击?
A:为每笔交易全局唯一添加 sequence_id 并存入链;节点验证是否已消耗即可杜绝。

Q5:测试网对显卡有要求吗?
A:演示难度默认 1~3,可以在笔记本 CPU 秒出块;若作压测,可手动上调 powTargetBits 观察算力需求。

Q6:能不能一键发布到公网?
A:将种子节点绑公网 IP,然后将 /src 打包进 Docker 镜像,一条命令即可拉取运行。区块链原理不变,只是 NAT 规则与防火墙需额外处理。


进阶方向推荐

  1. 共识算法实验

    • 切换 PoSmine 函数改为用链上验证者集合抽摇号。
    • 引入 BFT(实用拜占庭容错),在 3f+1 节点下容忍 f 个作恶节点。
  2. 持久化与分布式数据库

    • 把 LevelDB 换成 PostgreSQL/ MongoDB,实现 快照区块剪枝 减少磁盘占用。
    • 使用 Redis Stream 做低延迟同步。
  3. 轻节点 + SPV 验证

    • 客户端只保存区块头,交易验证由 Merkle 证明 完成,降低移动设备存储压力。
  4. 引入 Web3 前端

    • 用 Next.js + ethers.js 定义 钱包组件,无缝对接刚才搭建的 Node.js P2P 接口。

结语

全文用 1000+行 以内 JavaScript 代码完成了「区块 + 交易 + 钱包 + 挖矿 + 网络同步」的闭环。
掌握这些 区块链核心关键词 后,你就能看懂任何开源链的底层实现,继而参与 Node.js 区块链框架交易所撮合系统DeFi 合约对接 等高阶项目。

继续深入:把本链与主网币见证人 SDK 联动,亲手发一次 跨链桥资产映射,你会发现:去中心化世界的边界,只取决于你对代码的好奇心。