发布日期: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
九、总结与扩展
通过本教程,您已经掌握了:
- 区块链核心数据结构
- 加密算法与数字签名
- P2P网络通信
- 共识机制实现
- 交易验证系统
扩展学习方向:
- 智能合约实现
- 分片技术优化
- 零知识证明
- DApp开发