JavaScript区块链模拟器开发:从加密算法到P2P网络全流程实战 | 高级JS开发

发布日期:2024年10月10日

一、区块链核心架构

本教程将实现一个完整的区块链模拟系统,包含以下核心组件:

  • 加密模块:SHA256哈希与数字签名
  • 区块结构:默克尔树与工作量证明
  • 网络层:WebSocket P2P网络
  • 共识机制:PoW挖矿算法
  • 交易系统:UTXO模型实现

技术栈:ES6+ + Node.js + WebSocket + CryptoJS

二、项目初始化

1. 基础结构搭建

# 创建项目目录
mkdir js-blockchain
cd js-blockchain

# 初始化Node项目
npm init -y

# 安装核心依赖
npm install crypto-js ws uuid
npm install -D nodemon

2. 目录结构规划

src/
├── blockchain/     # 区块链核心
│   ├── block.js    # 区块类
│   └── chain.js    # 链类
├── crypto/         # 加密模块
│   ├── hash.js     # 哈希函数
│   └── keypair.js  # 密钥对
├── network/        # 网络层
│   ├── p2p.js      # P2P网络
│   └── api.js      # HTTP接口
├── transactions/   # 交易系统
│   ├── tx.js       # 交易类
│   └── pool.js     # 交易池
└── index.js        # 入口文件

三、加密模块实现

1. SHA256哈希函数

// src/crypto/hash.js
const { SHA256 } = require('crypto-js')

class Hash {
  static create(data) {
    return SHA256(JSON.stringify(data)).toString()
  }

  static verify(data, hash) {
    return this.create(data) === hash
  }

  static mineNonce(block) {
    let nonce = 0
    let hash = ''
    
    do {
      nonce++
      block.nonce = nonce
      hash = this.create(block)
    } while (!hash.startsWith('0000'))
    
    return nonce
  }
}

module.exports = Hash

2. 椭圆曲线数字签名

// src/crypto/keypair.js
const EC = require('elliptic').ec
const ec = new EC('secp256k1')
const { v4: uuidv4 } = require('uuid')

class KeyPair {
  constructor() {
    this.keyPair = ec.genKeyPair()
    this.publicKey = this.keyPair.getPublic('hex')
    this.privateKey = this.keyPair.getPrivate('hex')
    this.id = uuidv4()
  }

  sign(data) {
    const hash = require('./hash').create(data)
    return this.keyPair.sign(hash).toDER('hex')
  }

  static verifySignature(publicKey, signature, data) {
    const key = ec.keyFromPublic(publicKey, 'hex')
    const hash = require('./hash').create(data)
    return key.verify(hash, signature)
  }
}

module.exports = KeyPair

四、区块链核心实现

1. 区块类设计

// src/blockchain/block.js
const { createMerkleRoot } = require('../crypto/merkle')

class Block {
  constructor(index, timestamp, transactions, previousHash = '') {
    this.index = index
    this.timestamp = timestamp
    this.transactions = transactions
    this.previousHash = previousHash
    this.merkleRoot = createMerkleRoot(transactions)
    this.hash = this.calculateHash()
    this.nonce = 0
    this.difficulty = 4
  }

  calculateHash() {
    return require('../crypto/hash').create({
      index: this.index,
      timestamp: this.timestamp,
      transactions: this.transactions,
      previousHash: this.previousHash,
      merkleRoot: this.merkleRoot,
      nonce: this.nonce
    })
  }

  mineBlock() {
    while (!this.hash.startsWith('0'.repeat(this.difficulty))) {
      this.nonce++
      this.hash = this.calculateHash()
    }
    console.log(`区块挖出: ${this.hash}`)
  }

  hasValidTransactions() {
    for (const tx of this.transactions) {
      if (!tx.isValid()) return false
    }
    return true
  }
}

module.exports = Block

2. 区块链类实现

// src/blockchain/chain.js
const Block = require('./block')
const { GENESIS_DATA } = require('../config')

class Blockchain {
  constructor() {
    this.chain = [this.createGenesisBlock()]
    this.pendingTransactions = []
    this.miningReward = 100
    this.difficulty = 2
  }

  createGenesisBlock() {
    return new Block(
      0, 
      Date.now(), 
      [], 
      '0'.repeat(64),
      GENESIS_DATA.nonce
    )
  }

  getLatestBlock() {
    return this.chain[this.chain.length - 1]
  }

  addBlock(newBlock) {
    newBlock.previousHash = this.getLatestBlock().hash
    newBlock.mineBlock(this.difficulty)
    this.chain.push(newBlock)
  }

  minePendingTransactions(miningRewardAddress) {
    const rewardTx = new Transaction(
      null, 
      miningRewardAddress, 
      this.miningReward
    )
    this.pendingTransactions.push(rewardTx)

    const block = new Block(
      this.chain.length,
      Date.now(),
      this.pendingTransactions,
      this.getLatestBlock().hash
    )
    
    block.mineBlock(this.difficulty)
    console.log('区块成功挖出!')
    this.chain.push(block)

    this.pendingTransactions = []
  }

  isChainValid() {
    for (let i = 1; i < this.chain.length; i++) {
      const currentBlock = this.chain[i]
      const previousBlock = this.chain[i - 1]

      if (!currentBlock.hasValidTransactions()) {
        return false
      }

      if (currentBlock.hash !== currentBlock.calculateHash()) {
        return false
      }

      if (currentBlock.previousHash !== previousBlock.hash) {
        return false
      }
    }
    return true
  }
}

module.exports = Blockchain

五、P2P网络实现

1. WebSocket服务器

// src/network/p2p.js
const WebSocket = require('ws')
const Blockchain = require('../blockchain/chain')

class P2PServer {
  constructor(blockchain) {
    this.blockchain = blockchain
    this.sockets = []
    this.server = new WebSocket.Server({ port: 5001 })
  }

  listen() {
    this.server.on('connection', (socket) => {
      this.connectSocket(socket)
    })
    console.log('P2P服务器运行在: ws://localhost:5001')
  }

  connectSocket(socket) {
    this.sockets.push(socket)
    console.log('新的节点连接')

    this.messageHandler(socket)
    this.sendChain(socket)
  }

  messageHandler(socket) {
    socket.on('message', (message) => {
      const data = JSON.parse(message)
      
      switch(data.type) {
        case 'CHAIN':
          this.blockchain.replaceChain(data.chain)
          break
        case 'TRANSACTION':
          this.blockchain.addTransaction(data.transaction)
          break
      }
    })
  }

  sendChain(socket) {
    socket.send(JSON.stringify({
      type: 'CHAIN',
      chain: this.blockchain.chain
    }))
  }

  syncChains() {
    this.sockets.forEach(socket => {
      this.sendChain(socket)
    })
  }

  broadcastTransaction(transaction) {
    this.sockets.forEach(socket => {
      socket.send(JSON.stringify({
        type: 'TRANSACTION',
        transaction
      }))
    })
  }

  connectToPeers(newPeers) {
    newPeers.forEach(peer => {
      const socket = new WebSocket(peer)
      
      socket.on('open', () => {
        this.connectSocket(socket)
      })
    })
  }
}

module.exports = P2PServer

六、交易系统实现

1. 交易类设计

// src/transactions/tx.js
const { KeyPair } = require('../crypto/keypair')
const { Hash } = require('../crypto/hash')

class Transaction {
  constructor(fromAddress, toAddress, amount, inputs = [], outputs = []) {
    this.fromAddress = fromAddress
    this.toAddress = toAddress
    this.amount = amount
    this.inputs = inputs
    this.outputs = outputs
    this.timestamp = Date.now()
    this.hash = this.calculateHash()
    this.signature = ''
  }

  calculateHash() {
    return Hash.create({
      fromAddress: this.fromAddress,
      toAddress: this.toAddress,
      amount: this.amount,
      inputs: this.inputs,
      outputs: this.outputs,
      timestamp: this.timestamp
    })
  }

  signTransaction(keyPair) {
    if (keyPair.getPublic('hex') !== this.fromAddress) {
      throw new Error('你不能签署其他人的交易!')
    }
    
    this.signature = keyPair.sign(this.hash)
  }

  isValid() {
    if (this.fromAddress === null) return true // 挖矿奖励

    if (!this.signature || this.signature.length === 0) {
      throw new Error('交易没有签名!')
    }

    return KeyPair.verifySignature(
      this.fromAddress,
      this.signature,
      this.hash
    )
  }
}

module.exports = Transaction

2. UTXO交易池

// src/transactions/pool.js
class TransactionPool {
  constructor() {
    this.transactions = []
  }

  addTransaction(transaction) {
    if (!transaction.isValid()) {
      throw new Error('无效交易')
    }

    if (this.transactions.some(tx => tx.hash === transaction.hash)) {
      throw new Error('交易已存在')
    }

    this.transactions.push(transaction)
  }

  getValidTransactions() {
    return this.transactions.filter(tx => {
      try {
        return tx.isValid()
      } catch (err) {
        return false
      }
    })
  }

  clear() {
    this.transactions = []
  }
}

module.exports = TransactionPool

七、API接口设计

1. Express REST API

// src/network/api.js
const express = require('express')
const Blockchain = require('../blockchain/chain')
const P2PServer = require('./p2p')
const Transaction = require('../transactions/tx')
const KeyPair = require('../crypto/keypair')

class API {
  constructor(blockchain, p2pServer) {
    this.blockchain = blockchain
    this.p2pServer = p2pServer
    this.app = express()
    this.app.use(express.json())
    
    this.setupRoutes()
  }

  setupRoutes() {
    this.app.get('/blocks', (req, res) => {
      res.json(this.blockchain.chain)
    })

    this.app.post('/mine', (req, res) => {
      const block = new Block(
        this.blockchain.chain.length,
        Date.now(),
        this.blockchain.pendingTransactions,
        this.blockchain.getLatestBlock().hash
      )
      
      block.mineBlock(this.blockchain.difficulty)
      this.blockchain.chain.push(block)
      this.p2pServer.syncChains()
      
      res.json(block)
    })

    this.app.post('/transactions', (req, res) => {
      const { fromAddress, toAddress, amount } = req.body
      const transaction = new Transaction(fromAddress, toAddress, amount)
      
      try {
        this.blockchain.addTransaction(transaction)
        this.p2pServer.broadcastTransaction(transaction)
        res.json({ message: '交易已添加' })
      } catch (err) {
        res.status(400).json({ error: err.message })
      }
    })

    this.app.post('/peers', (req, res) => {
      const { peers } = req.body
      this.p2pServer.connectToPeers(peers)
      res.json({ message: '节点已连接' })
    })
  }

  listen(port) {
    this.app.listen(port, () => {
      console.log(`API运行在: http://localhost:${port}`)
    })
  }
}

module.exports = API

八、系统集成与测试

1. 主程序入口

// src/index.js
const Blockchain = require('./blockchain/chain')
const P2PServer = require('./network/p2p')
const API = require('./network/api')
const KeyPair = require('./crypto/keypair')

// 初始化组件
const blockchain = new Blockchain()
const p2pServer = new P2PServer(blockchain)
const api = new API(blockchain, p2pServer)

// 生成测试密钥
const keyPair = new KeyPair()
console.log('测试密钥对:')
console.log('公钥:', keyPair.publicKey)
console.log('私钥:', keyPair.privateKey)

// 启动服务
p2pServer.listen()
api.listen(3000)

// 添加测试交易
const tx = new Transaction(keyPair.publicKey, 'recipient-address', 50)
tx.signTransaction(keyPair)
blockchain.addTransaction(tx)

// 模拟挖矿
setTimeout(() => {
  blockchain.minePendingTransactions(keyPair.publicKey)
  p2pServer.syncChains()
}, 5000)

2. 测试方法

# 启动第一个节点
node src/index.js

# 启动第二个节点(新终端)
HTTP_PORT=3001 P2P_PORT=5002 PEERS=ws://localhost:5001 node src/index.js

# 测试API
curl http://localhost:3000/blocks
curl -X POST http://localhost:3000/transactions -H "Content-Type: application/json" -d '{"fromAddress":"sender-address","toAddress":"recipient-address","amount":50}'
curl -X POST http://localhost:3000/mine

九、总结与扩展

通过本教程,您已经掌握了:

  1. 区块链核心数据结构
  2. 加密算法与数字签名
  3. P2P网络通信
  4. 共识机制实现
  5. 交易验证系统

扩展学习方向:

  • 智能合约实现
  • 分片技术优化
  • 零知识证明
  • DApp开发
JavaScript区块链模拟器开发:从加密算法到P2P网络全流程实战 | 高级JS开发
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

淘吗网 javascript JavaScript区块链模拟器开发:从加密算法到P2P网络全流程实战 | 高级JS开发 https://www.taomawang.com/web/javascript/904.html

常见问题

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务