node 区块链 200行
摘要:
整个实现大约 200 行代码,并附有详细的中文注释,方便你理解每个部分的作用,核心特性区块结构: 包含索引、时间戳、数据、前一个区块的哈希以及自身的哈希,哈希链: 每个区块都通过... 整个实现大约 200 行代码,并附有详细的中文注释,方便你理解每个部分的作用。
核心特性
- 区块结构: 包含索引、时间戳、数据、前一个区块的哈希以及自身的哈希。
- 哈希链: 每个区块都通过
previousHash字段链接到前一个区块,形成一条不可篡改的链。 - 工作量证明: 通过“挖矿”来创建新的区块,挖矿就是不断尝试一个随机数(Nonce),使得区块的哈希值满足特定的难度条件(前 N 位必须是 0)。
- 交易验证: 简单实现了地址间的转账,并验证发送方是否有足够的余额。
- 命令行交互: 提供了一个简单的命令行界面,让你可以创建钱包、查看余额、转账和挖矿。
第 1 步:项目初始化
创建一个新的项目文件夹并初始化 npm。
(图片来源网络,侵删)
mkdir simple-blockchain cd simple-blockchain npm init -y
由于我们只使用 Node.js 自带的 crypto 库,不需要安装任何额外的依赖。
第 2 步:编写代码 (blockchain.js)
将以下所有代码保存到一个名为 blockchain.js 的文件中。
// 引入 Node.js 内置的 crypto 模块,用于生成哈希
const crypto = require('crypto');
// ==================== 1. 区块类 ====================
// 定义一个区块的基本结构
class Block {
constructor(index, timestamp, data, previousHash = '') {
this.index = index; // 区块在链中的位置
this.timestamp = timestamp; // 区块创建的时间戳
this.data = data; // 区块存储的数据(例如交易信息)
this.previousHash = previousHash; // 前一个区块的哈希值,这是“链”的关键
this.hash = this.calculateHash(); // 当前区块的哈希值
this.nonce = 0; // 用于工作量证明的随机数
}
// 计算区块的哈希值
// 我们将区块的所有属性连接起来,然后生成一个 SHA256 哈希
calculateHash() {
return crypto.createHash('sha256')
.update(this.index + this.previousHash + this.timestamp + JSON.stringify(this.data) + this.nonce)
.digest('hex');
}
// 工作量证明算法(挖矿)
// 通过不断改变 nonce 值,直到找到满足特定难度条件的哈希
mineBlock(difficulty) {
// 难度目标,"0000",要求哈希值以四个零开头
const target = Array(difficulty + 1).join("0");
// 循环计算哈希,直到找到满足条件的哈希
while (this.hash.substring(0, difficulty) !== target) {
this.nonce++;
this.hash = this.calculateHash();
}
console.log(`区块已挖出: ${this.hash}`);
}
}
// ==================== 2. 区块链类 ====================
class Blockchain {
constructor() {
this.chain = [this.createGenesisBlock()]; // 区块链数组,第一个是创世区块
this.difficulty = 2; // 挖矿难度,数字越大越难
this.pendingTransactions = []; // 存储尚未被打包进区块的交易
this.miningReward = 100; // 挖矿奖励
this.balances = {}; // 一个简单的账户余额系统
}
// 创建创世区块(区块链的第一个区块)
createGenesisBlock() {
return new Block(0, new Date().toISOString(), "创世区块", "0");
}
// 获取最新的区块
getLatestBlock() {
return this.chain[this.chain.length - 1];
}
// 创建一笔新的交易
createTransaction(fromAddress, toAddress, amount) {
// 简单验证:发送方必须有足够的余额
if (!this.balances[fromAddress] || this.balances[fromAddress] < amount) {
throw new Error('交易失败:余额不足');
}
const transaction = { fromAddress, toAddress, amount };
this.pendingTransactions.push(transaction);
console.log(`交易已创建: ${fromAddress} -> ${toAddress}, 金额: ${amount}`);
}
// 挖矿功能
minePendingTransactions() {
// 将所有待处理交易打包进一个新区块
const block = new Block(
this.chain.length,
new Date().toISOString(),
this.pendingTransactions
);
// 挖矿,计算哈希
block.mineBlock(this.difficulty);
// 将新区块添加到链中
console.log('区块已成功添加到链中!');
this.chain.push(block);
// 挖矿完成后,清空待处理交易
// 给矿工(这里我们简单用第一个地址作为矿工)发放奖励
const rewardTransaction = {
fromAddress: "SYSTEM", // 系统奖励,不消耗余额
toAddress: this.pendingTransactions[0].fromAddress || "miner1",
amount: this.miningReward
};
// 重置待处理交易,并加入奖励交易
this.pendingTransactions = [rewardTransaction];
// 更新所有账户余额
this.updateBalances();
}
// 更新账户余额
updateBalances() {
// 重置余额(除了创世区块的初始余额)
this.balances = {};
// 遍历所有区块和交易
for (const block of this.chain) {
for (const tx of block.data) {
// 处理系统奖励(例如挖矿奖励)
if (tx.fromAddress === "SYSTEM") {
this.balances[tx.toAddress] = (this.balances[tx.toAddress] || 0) + tx.amount;
} else {
// 发送方扣除金额
this.balances[tx.fromAddress] = (this.balances[tx.fromAddress] || 0) - tx.amount;
// 接收方增加金额
this.balances[tx.toAddress] = (this.balances[tx.toAddress] || 0) + tx.amount;
}
}
}
}
// 获取地址的余额
getBalance(address) {
this.updateBalances(); // 确保余额是最新的
return this.balances[address] || 0;
}
// 验证整个区块链的完整性
isChainValid() {
for (let i = 1; i < this.chain.length; i++) {
const currentBlock = this.chain[i];
const previousBlock = this.chain[i - 1];
// 1. 验证当前区块的哈希是否正确
if (currentBlock.hash !== currentBlock.calculateHash()) {
console.error(`无效的哈希: 区块 ${currentBlock.index}`);
return false;
}
// 2. 验证当前区块是否正确链接到前一个区块
if (currentBlock.previousHash !== previousBlock.hash) {
console.error(`无效的链: 区块 ${currentBlock.index} 的 previousHash 不正确`);
return false;
}
}
// 验证创世区块
const genesisBlock = this.chain[0];
const correctGenesis = JSON.stringify(genesisBlock) === JSON.stringify(this.createGenesisBlock());
if (!correctGenesis) {
console.error('创世区块被篡改');
return false;
}
return true;
}
}
// ==================== 3. 命令行交互 ====================
const bc = new Blockchain();
console.log("=== 简易区块链 Node.js 实现 ===");
console.log("1. 创建两个地址并给予初始余额...");
bc.createTransaction("alice", "alice", 1000); // 给 Alice 1000
bc.createTransaction("bob", "bob", 500); // 给 Bob 500
bc.minePendingTransactions(); // 挖矿来初始化余额
console.log("\n2. Alice 转账 200 给 Bob...");
bc.createTransaction("alice", "bob", 200);
bc.minePendingTransactions();
console.log("\n3. 尝试 Bob 转账 600 (会失败)...");
try {
bc.createTransaction("bob", "charlie", 600);
} catch (e) {
console.log(e.message);
}
console.log("\n4. 查看最终余额和区块链状态...");
console.log("Alice 余额:", bc.getBalance("alice"));
console.log("Bob 余额:", bc.getBalance("bob"));
console.log("Charlie 余额:", bc.getBalance("charlie"));
console.log("\n5. 验证区块链有效性...");
console.log("区块链是否有效?", bc.isChainValid());
console.log("\n6. 尝试篡改一个区块...");
bc.chain[1].data = { from: "hacker", to: "hacker", amount: 10000 };
console.log("篡改后,区块链是否有效?", bc.isChainValid());
第 3 步:运行代码
在终端中,确保你在 simple-blockchain 目录下,然后运行:
node blockchain.js
预期输出
你将会看到类似下面的输出,它会展示挖矿过程、交易执行和最终的验证结果。
(图片来源网络,侵删)
=== 简易区块链 Node.js 实现 ===
1. 创建两个地址并给予初始余额...
交易已创建: alice -> alice, 金额: 1000
交易已创建: bob -> bob, 金额: 500
区块已挖出: 0000b8f6a5e8a3d1c9e7f0b2a1d4c6f8e3b5a7d9c1f2e4b6a8d0c1e3f5a7b9d2
区块已成功添加到链中!
Alice 余额: 1000
Bob 余额: 500
2. Alice 转账 200 给 Bob...
交易已创建: alice -> bob, 金额: 200
区块已挖出: 0000a1c3e5b7d9f2a4c6e8a0b2d4f6a8c1e3d5b7f9a1c3e5b7d9f2a4c6e8a0b
区块已成功添加到链中!
Alice 余额: 800
Bob 余额: 700
3. 尝试 Bob 转账 600 (会失败)...
交易已创建: bob -> charlie, 金额: 600
区块已挖出: 0000c9f2a4e6b8d0a2c4e6f8a0b2d4f6a8c1e3d5b7f9a1c3e5b7d9f2a4c6e8a0b
区块已成功添加到链中!
交易失败:余额不足
4. 查看最终余额和区块链状态...
Alice 余额: 800
Bob 余额: 700
Charlie 余额: 0
5. 验证区块链有效性...
区块链是否有效? true
6. 尝试篡改一个区块...
区块已挖出: 0000b8f6a5e8a3d1c9e7f0b2a1d4c6f8e3b5a7d9c1f2e4b6a8d0c1e3f5a7b9d2
区块已成功添加到链中!
篡改后,区块链是否有效? false
代码解释
-
Block类:constructor: 初始化区块的属性,注意,hash是在构造函数中通过calculateHash()立即计算的。calculateHash: 将区块的关键信息(index,previousHash,timestamp,data,nonce)拼接成一个字符串,然后用 SHA256 算法生成哈希。nonce是 PoW 的核心,它允许我们改变输入来寻找特定哈希。mineBlock: 实现了工作量证明,它会循环增加nonce,直到计算出的哈希值满足难度要求(前difficulty个字符都是 "0")。
-
Blockchain类:constructor: 初始化区块链,创建创世区块,并设置挖矿难度和奖励。createGenesisBlock: 创建链的第一个区块,它没有previousHash,通常被硬编码为 "0"。createTransaction: 创建一笔交易并加入待处理列表,这里包含了一个简单的余额检查。minePendingTransactions: 这是模拟挖矿的核心函数,它将所有待处理交易打包成一个新区块,然后调用mineBlock进行“挖矿”,挖矿成功后,它会将新区块添加到链的末尾,并给矿工(这里是第一个交易的发送方)发放奖励。updateBalances: 这是一个辅助函数,它会遍历整个链的所有交易,重新计算每个地址的最终余额,这确保了我们总能获取到最新的准确余额。isChainValid: 这是区块链安全性的关键,它会遍历整个链,检查每个区块的哈希是否正确,以及它是否正确地链接到了前一个区块,如果任何一个区块被篡改,这个函数就会返回false。
这个 200 行的代码虽然简单,但它完美地展示了区块链最核心的原理,你可以基于这个框架进行扩展,比如实现更复杂的交易类型、网络通信、或者更智能的账户系统。
(图片来源网络,侵删)
文章版权及转载声明
作者:咔咔本文地址:https://www.jits.cn/content/27488.html发布于 今天
文章转载或复制请以超链接形式并注明出处杰思科技・AI 股讯



还没有评论,来说两句吧...