Skip to content

区块链基础

导航目录

一、为什么需要区块链?—— 传统系统的四大痛点与区块链解法

痛点传统系统问题区块链解决方案类比
单点故障银行服务器宕机导致支付中断分布式节点网络(7×24 小时持续运行)多个备用水库 vs 单个大坝
数据篡改管理员可后台修改数据库记录哈希链 + 共识机制(需控制 51% 节点防伪水印 + 多人监考
中介成本高跨境支付手续费可高达 $50点对点交易(比特币手续费通常 < $1)跳过旅行社直订机票
隐私泄露中心化数据库被黑客集中攻击非对称加密(私钥由用户自主保管)保险箱钥匙自己拿 vs 交给物业保管

核心价值
去信任化:依靠数学与代码共识,而非中心机构背书。
抗审查性:数据分布式存储,无单一控制点可以“关停系统”。

二、代码如何建立信任?—— 智能合约的四大信任支柱

  1. 代码开源可验证

    • 合约字节码与源码公开(如在 Etherscan 上查看),全球开发者可以共同审计。
    • 类比:餐厅后厨全透明,顾客随时可以“看后厨”。
  2. 确定性执行

    • 所有节点通过 EVM(以太坊虚拟机)执行完全相同的字节码,给定相同输入,输出必然一致。
    • 技术要点:字节码级复现,避免“我电脑上显示不一样”的主观争议。
  3. 防篡改存储

    • 合约代码和状态写入区块链,任何修改都必须通过链上交易完成并支付 Gas
    • 安全门槛:理论上需要掌控超过 51% 算力 / 节点 才可能恶意篡改。
  4. 自动触发机制

    • 当满足设定条件(时间戳、价格触发、投票结果等)时自动执行代码逻辑。
    • 现实映射:自动售货机——投币达到金额后,自动出货,无需工作人员“点确认”。

Solidity 合约安全示例(防重入攻击)

solidity
contract SecureWithdrawal {
    mapping(address => uint256) public balances;
    bool private locked; // 互斥锁,防止同一函数被重入调用

    function withdraw() public {
        require(!locked, "Reentrancy guard");
        locked = true;

        uint256 amount = balances[msg.sender];
        require(amount > 0, "No balance");

        balances[msg.sender] = 0;
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");

        locked = false;
    }
}

关键逻辑说明
通过互斥锁 locked先更新余额再转账,阻止攻击者在回调中重复调用 withdraw,避免类似 The DAO 的重入漏洞。

三、去中心化网络是什么?—— 从微信群到区块链的进化

场景中心化模式去中心化模式优势
消息传递微信群主转述(依赖平台服务器)点对点广播(如 BitTorrent)群主失联不影响消息存档
文件存储百度网盘单点存储IPFS 分布式存储服务器故障不影响文件访问
货币交易银行系统清算(T+1 或更久到账)区块链点对点转账(约 10 分钟确认)接近实时到账,且无多级中间商扣费

核心区别
控制权转移:从“把数据托管给平台”转变为“用户自己拥有数据主权”。
容错性提升:部分节点宕机不影响整体网络运行,没有单点故障

四、区块链结构怎么运作?—— 带锁的“日记本链”

  1. 区块结构

    • 数据层:记录交易明细(例如:“A 向 B 转账 1 BTC”)。
    • 元数据:前一区块哈希、时间戳、难度目标、Nonce 等。
    • 类比:每一页日记都写着上一页的“摘要指纹”,改动任意一页都会导致后续所有页的指纹失效。
  2. 链式连接

    • 每个区块头中包含前一区块的哈希值,例如:Hash(Block N) = SHA256(Header)
    • 篡改难度:修改某个历史区块,必须重新计算该区块及之后所有区块的哈希,且还要在算力上“追平并超过”当前最长链,成本极高。
  3. 动态扩展

    • 矿工竞争打包交易,生成新区块并链接到链尾。
    • 最长链原则:网络约定“工作量最大的一条链为主链”,临时分叉会在后续出块中自然被抛弃。

五、非对称密码学是什么?—— 私钥即主权

概念技术实现现实映射
私钥256 位高熵随机数(如 3a7f...保险箱钥匙(丢失则资产永久丢失)
公钥由私钥通过椭圆曲线算法推导保险箱编号(公开,用于接收资产)
数字签名使用私钥对交易摘要进行签名信封上的火漆印章(验证来源与未被篡改)

安全原理(必须理解)
不可逆性:通过公钥几乎不可能反推出私钥,是典型的单向函数。
唯一性:私钥与公钥一一对应,一个私钥对应唯一一组身份

六、PoW 共识机制—— 算力即“投票权”

  1. 核心流程

    • 矿工竞争:通过哈希碰撞(如 SHA256(BlockHeader + Nonce))寻找满足难度目标的 Nonce。
    • 中奖规则:区块头哈希值的前 N 位为 0(难度越高,前导 0 越多)。
    • 奖励机制:率先找到合法哈希的矿工,会广播新区块并获得区块奖励(新发行的币 + 交易手续费)。
  2. 难度调整

    • 目标:维持全网平均约 10 分钟出一个新区块(以比特币为例)。
    • 机制:每 2016 个区块(约两周)根据实际出块总时间动态调整难度值。
    • 公式新难度 = 旧难度 × (实际时间 / 目标时间)
  3. 51% 攻击成本(以 2023 年比特币为例)

    参数值(近似量级)
    全网算力400 EH/s(4 × 10²⁰ 次哈希 / 秒)
    攻击所需算力> 200 EH/s(控制超过 51% 算力)
    矿机成本$50 / TH(1 TH = 10¹² 次哈希 / 秒)
    设备成本约 200×10⁶ TH × $50 ≈ $100 亿
    电力成本(每时)约 200 EH/s × 0.1 kW/TH × $0.1/kWh ≈ $200 万 / 小时

经济合理性
发动 51% 攻击的成本远高于可能获得的经济收益,且一旦成功攻击导致市场失去信心、币价暴跌,攻击者自身持有资产也会严重贬值,形成强烈的经济威慑。

七、现实场景速懂—— 区块链如何改变生活?

  1. 跨境汇款

    维度传统银行区块链
    耗时约 3 天(多国银行中转)约 10 分钟(点对点直达)
    费用约 $50 手续费通常 < $1 手续费
    风险中转行额外扣款 / 汇率损失等链上直达,无多级中间商
  2. 网购纠纷

    • 传统流程
      买家投诉 → 平台介入 → 举证拉扯 → 多方人工审核,通常耗时数日甚至数周。

    • 区块链方案
      使用 托管支付(Escrow)类型的智能合约 自动执行结算逻辑:

      solidity
      if (buyerConfirmed) {
          releaseFunds(seller);
      } else if (block.timestamp > expireAt) {
          refund(buyer);
      }
    • 优势:结算规则事先约定且不可篡改,零人工干预,可 7×24 小时自动结算,极大降低争议空间。

硬分叉与软分叉:区块链协议升级的两条路径

一、核心定义与本质区别

维度硬分叉(Hard Fork)软分叉(Soft Fork)
兼容性不兼容旧版本,旧节点会拒绝新规则区块向后兼容,旧节点可以接受新规则区块
网络影响极易分裂为两条独立链(如 ETH/ETC、BTC/BCH)一般保持单链运行,旧区块可能成为“孤儿区块”
升级要求需要绝大多数节点强制升级才能留在新链允许部分节点先升级,未升级节点仍能验证旧规则区块
典型案例以太坊 DAO 事件分叉、比特币现金分叉比特币 SegWit 升级、BIP-66 签名验证规则强化

二、技术实现与案例解析

1. 硬分叉:协议的根本性变更

  • 技术特征
    直接修改核心规则,例如:调整区块大小、改变共识算法、修改交易格式等,旧节点因规则不一致而拒绝新链区块。
  • 典型案例
    • 以太坊 ETH/ETC 分叉
      2016 年 The DAO 事件后,以太坊通过硬分叉回滚被盗资金,部分社区成员拒绝此做法,坚持原链规则,最终形成两条链。
      结果:保留原历史记录的 ETC 与主流采用新规则的 ETH 并存。
    • 比特币 BTC/BCH 分叉
      2017 年围绕扩容争议,部分矿工支持更大的区块上限,从而分叉出比特币现金(BCH)。
      结果:BTC 继续使用 1 MB 区块上限,BCH 则采用更大的区块大小。

2. 软分叉:向后兼容的渐进式升级

  • 技术特征
    在不改变“旧规则允许的全部行为”的前提下收紧规则,新功能在支持新版客户端的节点上生效,旧节点仍然可以把新区块视为合法。
  • 典型案例
    • 比特币 SegWit 升级
      2017 年通过软分叉将签名从交易主体中分离,等效提升了区块容量(可容纳更多交易)。
      结果:未升级节点仍可验证旧格式交易,网络整体未出现长期分裂。
    • BIP-66 签名验证规则强化
      2015 年比特币通过软分叉强化了签名 DER 编码规则,未升级节点可能产生不符合新规则的区块,新节点会拒绝接受。
      结果:矿工逐步统一升级,旧规则产出的区块被网络自然淘汰。

挖矿流程代码示例(PoW 简化模拟)

  • 目标哈希公式:hash = sha256(交易数据 + 上一个区块哈希 + 随机数 Nonce)
js
// pow.js
const crypto = require("crypto");

// 简化的挖矿模拟器
async function mineBlock(difficulty, transactions, previousHash) {
  const prefix = "0".repeat(difficulty);
  console.log(`开始挖矿,目标:哈希值以 ${prefix} 开头...`);

  let nonce = 0; // 随机数
  let hashCount = 0; // 哈希计算次数
  const startTime = Date.now(); // 挖矿开始时间

  while (true) {
    hashCount++;
    const blockHeader = `${transactions}${previousHash}${nonce}`;
    const hash = crypto.createHash("sha256").update(blockHeader).digest("hex");

    // 检查哈希值是否符合难度要求
    if (hash.startsWith(prefix)) {
      const elapsedTime = (Date.now() - startTime) / 1000;
      console.log(`\n成功挖到区块!`);
      console.log(`尝试次数:${hashCount}`);
      console.log(`耗时:${elapsedTime.toFixed(2)} 秒`);
      console.log(`Nonce:${nonce}`);
      console.log(`哈希值:${hash}`);
      break;
    }

    nonce++;

    // 每 1000 次更新一次状态
    if (hashCount % 1000 === 0) {
      process.stdout.write(`\r已尝试 ${hashCount} 次哈希计算...`);
    }
  }
}

// 难度系数:要求前多少位哈希值为 0
const difficulty = 6;
// 交易数据
const transactions = "Alice sends 1 BTC to Bob";
// 上一个区块的哈希值(示例数据)
const previousHash =
  "0000a8c0d36295638e8a4e9b45a3e3e9d3e8c7b1a3e8e8e8e8e8e8e8e8e8e8e8";

mineBlock(difficulty, transactions, previousHash).catch((err) => {
  console.error("错误:", err);
});
shell
node pow.js

开始挖矿,目标:哈希值以 000000 开头...
已尝试 49619000 次哈希计算...
成功挖到区块!
尝试次数:49619265
耗时:74.62
Nonce:49619264
哈希值:000000718f3ee008a8d7a76e21315d33f4a773f5339595fc0d5f21d4ad69e620

交易签名与验证代码示例

js
const crypto = require("crypto");

/**
 * 生成 RSA 密钥对
 * @returns {{ publicKey: string; privateKey: string }}
 */
function generateRSAKey() {
  const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
    modulusLength: 2048,
    publicKeyEncoding: {
      type: "spki",
      format: "pem",
    },
    privateKeyEncoding: {
      type: "pkcs8",
      format: "pem",
    },
  });

  return { publicKey, privateKey };
}

/**
 * 使用公钥加密数据
 * @param {string|Buffer} data 要加密的数据
 * @param {string} publicKey 公钥
 * @returns {string} 加密后的 base64 字符串
 */
function encryptWithPublicKey(data, publicKey) {
  const buffer = Buffer.from(data);
  const encrypted = crypto.publicEncrypt(
    {
      key: publicKey,
      padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
      oaepHash: "sha256",
    },
    buffer
  );
  return encrypted.toString("base64");
}

/**
 * 使用私钥解密数据
 * @param {string} encryptedData 加密的 base64 数据
 * @param {string} privateKey 私钥
 * @returns {string} 解密后的原始数据
 */
function decryptWithPrivateKey(encryptedData, privateKey) {
  const buffer = Buffer.from(encryptedData, "base64");
  const decrypted = crypto.privateDecrypt(
    {
      key: privateKey,
      padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
      oaepHash: "sha256",
    },
    buffer
  );
  return decrypted.toString();
}

/**
 * 使用私钥对数据进行签名
 * @param {string|Buffer} data 要签名的数据
 * @param {string} privateKey 私钥
 * @returns {string} 签名的 base64 表示
 */
function signData(data, privateKey) {
  const sign = crypto.createSign("SHA256");
  sign.update(data);
  sign.end();
  return sign.sign(privateKey, "base64");
}

/**
 * 使用公钥验证签名
 * @param {string|Buffer} data 原始数据
 * @param {string} signature 签名的 base64 字符串
 * @param {string} publicKey 公钥
 * @returns {boolean} 验证是否成功
 */
function verifySignature(data, signature, publicKey) {
  const verify = crypto.createVerify("SHA256");
  verify.update(data);
  verify.end();
  return verify.verify(publicKey, signature, "base64");
}
js
/**
 * 非对称加密与签名的完整演示
 */
function demo() {
  console.log("非对称加密完整演示\n");

  // 生成密钥对
  const { publicKey, privateKey } = generateRSAKey();
  console.log("RSA 密钥对已生成");

  const originalMessage = "这是需要保密的重要数据:Hello, RSA Encryption!";
  console.log(`\n原始消息: ${originalMessage}`);

  // 演示 1:公钥加密 → 私钥解密(保证保密性)
  console.log("\n=== 1. 公钥加密 & 私钥解密(保密性)===");

  const encrypted = encryptWithPublicKey(originalMessage, publicKey);
  console.log(`加密后 (base64): ${encrypted.substring(0, 80)}...`);

  const decrypted = decryptWithPrivateKey(encrypted, privateKey);
  console.log(`解密后: ${decrypted}`);
  console.log(`加解密成功: ${originalMessage === decrypted}`);

  // 演示 2:私钥签名 → 公钥验证(身份与完整性)
  console.log("\n=== 2. 私钥签名 & 公钥验证(身份验证 + 防篡改)===");

  const signature = signData(originalMessage, privateKey);
  console.log(`数字签名 (base64): ${signature.substring(0, 80)}...`);

  const isValid = verifySignature(originalMessage, signature, publicKey);
  console.log(`签名验证结果: ${isValid ? "有效 - 数据完整且来源可信" : "无效"}`);

  // 演示 3:篡改检测
  console.log("\n=== 3. 篡改检测演示 ===");
  const tamperedMessage = "这是被篡改的重要数据:Hello, RSA Encryption!";
  const isTamperedValid = verifySignature(
    tamperedMessage,
    signature,
    publicKey
  );
  console.log(
    `篡改后验证: ${isTamperedValid ? "错误 - 居然验证通过" : "无效 - 成功检测到数据被篡改"}`
  );
}

demo();

/**
 * 模拟 Alice 与 Bob 的安全消息传递
 */
function secureMessagingDemo() {
  console.log("\n\n安全消息传递系统演示");
  console.log("=".repeat(50));

  // 模拟两个用户
  const aliceKeys = generateRSAKey();
  const bobKeys = generateRSAKey();

  console.log("Alice 和 Bob 已生成各自的密钥对");

  // Alice 发送加密消息给 Bob
  const messageToBob = "Bob,这是我们项目的机密信息!";
  console.log(`\nAlice 发送给 Bob: ${messageToBob}`);

  // 1. Alice 用 Bob 的公钥加密(确保只有 Bob 能解密)
  const encryptedMessage = encryptWithPublicKey(
    messageToBob,
    bobKeys.publicKey
  );

  // 2. Alice 用自己的私钥签名(证明“确实是我发的”)
  const messageSignature = signData(messageToBob, aliceKeys.privateKey);

  console.log("Alice: 消息已加密并签名");

  // Bob 接收消息
  console.log("\nBob 接收消息:");

  try {
    // 1. Bob 用自己的私钥解密
    const decryptedMessage = decryptWithPrivateKey(
      encryptedMessage,
      bobKeys.privateKey
    );
    console.log(`解密后的消息: ${decryptedMessage}`);

    // 2. Bob 用 Alice 的公钥验证签名
    const signatureValid = verifySignature(
      decryptedMessage,
      messageSignature,
      aliceKeys.publicKey
    );

    if (signatureValid) {
      console.log("签名验证成功: 消息确实来自 Alice,且未被篡改");
    } else {
      console.log("警告: 签名验证失败!消息可能被伪造或篡改");
    }
  } catch (error) {
    console.log("解密失败:", error.message);
  }
}

secureMessagingDemo();