跳到主要内容

区块链与以太坊基础

概述

区块链是 Web3 的底层基础设施,以太坊则是前端开发者最常接触的公链。理解区块链的运作原理和以太坊的核心概念,是开发 DApp、与智能合约交互的前提。本文从前端开发者的视角,梳理区块链与以太坊的核心知识。

面试要点

面试中关于区块链的考察通常不会太深入底层密码学,而是侧重于你对账户模型交易结构Gas 机制EVM 等概念的理解——这些直接影响前端 DApp 的开发方式。

如果你还没有阅读 Web3 知识体系概览,建议先看 Web3 知识体系概览,了解整体知识地图。

面试速答版

区块链与以太坊需要掌握什么? 前端面试不会问底层密码学,但这几个概念必须明白:

  • 账户模型:以太坊是账户模型(不同于 BTC 的 UTXO),分 EOA(外部账户、有私钥)和合约账户两种。
  • EVM:以太坊虚拟机,是一个栈式虚拟机,所有 EVM 兼容链(Polygon、BSC、Arbitrum、Optimism)都跑同样的字节码。
  • Gas:每个操作都要消耗计算资源(gasUsed × gasPrice),合约函数越复杂 Gas 越高。
  • 共识机制:以太坊已从 PoW 转为 PoS(合并后),出块交由验证者。
  • Layer 2:Arbitrum/Optimism(Optimistic Rollup)、zkSync(ZK Rollup)把交易打包后上 L1,用以太坊安全但 Gas 低一两个数量级。

区块链核心概念

什么是区块链

区块链本质上是一个分布式、不可篡改的账本。交易数据被打包成「区块」,通过密码学哈希依次链接,形成一条链。

三个核心特性:

特性说明对前端开发的影响
去中心化没有单一控制方,由全网节点共同维护数据读取通过 RPC 节点(Infura、Alchemy),无传统后端
不可篡改一旦写入,数据几乎不可被修改交易一旦确认就无法撤销,需做好 UI 确认流程
透明公开所有交易记录对所有人可见用户行为全部链上可查,隐私需额外处理

区块结构

每个区块包含区块头交易列表两部分,区块头记录元信息,交易列表存储实际交易。

Merkle Tree

Merkle Tree(默克尔树)是一种哈希二叉树,用于高效验证某笔交易是否包含在区块中。前端使用 Merkle Proof 可以实现白名单验证(如 NFT Mint 白名单),而无需将整个列表存储在链上。

区块头关键字段:

字段说明
parentHash上一个区块头的哈希,形成链式结构
stateRoot世界状态树的根哈希(所有账户余额、合约存储的快照)
transactionsRoot交易 Merkle Tree 的根哈希
receiptsRoot收据 Merkle Tree 的根哈希(包含交易执行结果、日志)
number区块高度(从 0 开始递增)
timestamp区块产生的时间戳
gasUsed该区块中所有交易消耗的 Gas 总量
baseFeePerGasEIP-1559 引入的基础费用(会被销毁)

共识机制

共识机制决定了谁有权生产新区块。以太坊经历了从 PoWPoS 的重大转变:

特性PoW(工作量证明)PoS(权益证明)
原理矿工通过算力竞争解题出块验证者质押 ETH,被随机选中出块
以太坊使用时期创世 ~ 2022.9(The Merge)2022.9 至今
能耗极高(大量算力消耗)极低(降低 ~99.95% 能耗)
出块时间~13 秒(不稳定)固定 12 秒(每个 Slot)
最终性概率性最终性(需等多个区块确认)确定性最终性(约 12.8 分钟,2 个 Epoch)
参与门槛购买矿机质押 32 ETH 成为验证者
The Merge 对前端的影响

The Merge(合并)后出块时间从不稳定的 ~13 秒变为固定的 12 秒,这对前端的交易等待 UI区块确认轮询逻辑都有影响。部分依赖 block.difficulty 的旧代码也需要适配(PoS 下该字段被替换为 prevrandao)。

以太坊架构

EVM(以太坊虚拟机)

EVM(Ethereum Virtual Machine)是以太坊的执行引擎,是一个基于栈的虚拟机,所有节点运行相同的 EVM 来执行智能合约,保证结果一致。

前端开发者需要理解的 EVM 要点:

  • EVM 执行合约代码需要消耗 Gas,Gas 不足会导致交易回滚
  • 合约调用分为读操作call,免费)和写操作transaction,消耗 Gas)
  • 合约执行过程中会产生事件日志(Events),前端通过监听事件来更新 UI

以太坊是一个状态机

以太坊本质上是一个交易驱动的状态机

状态(S) + 交易(T) → 新状态(S')

世界状态(World State) 记录了所有账户的当前状态,每笔交易都会触发状态转换。前端通过 eth_call 读取当前状态,通过 eth_sendTransaction 提交交易来改变状态。

账户模型

以太坊有两种账户类型,理解它们的区别是前端 Web3 开发的基础:

EOA vs 合约账户

特性EOA(外部账户)合约账户
控制方式由私钥控制由合约代码控制
地址格式20 字节,如 0xAbC...12320 字节,由部署者地址 + nonce 派生
有无代码有(EVM 字节码)
能否发起交易✅ 可以❌ 不能主动发起,只能被调用
有无存储仅有余额和 nonce有余额、nonce、代码和存储
创建方式生成密钥对即可通过部署交易创建
典型示例MetaMask 钱包地址Uniswap 路由合约、ERC-20 代币合约
账户抽象(Account Abstraction)

ERC-4337 提出了账户抽象的概念,允许合约账户像 EOA 一样发起交易。这为社交恢复、无 Gas 交易、批量交易等功能提供了可能。前端开发者需要关注这个趋势,因为它会改变钱包连接和交易签名的方式。

账户状态字段

以太坊账户状态
interface AccountState {
nonce: number; // 该账户发起的交易数(EOA)或创建的合约数(合约账户)
balance: bigint; // 账户余额(单位:Wei,1 ETH = 10^18 Wei)
storageRoot: string; // 存储树的根哈希(仅合约账户有实际内容)
codeHash: string; // 合约代码的哈希(EOA 为空哈希 keccak256(""))
}

Gas 机制

Gas 是以太坊的「燃料」,用于衡量执行操作的计算成本。前端开发者必须理解 Gas 机制,因为它直接影响交易费用估算用户体验

Gas 基本概念

概念说明
Gas执行操作的计量单位,每个 EVM 操作码有固定 Gas 消耗
Gas Limit交易发送者愿意为这笔交易支付的 Gas 上限
Gas Used交易实际消耗的 Gas(多余的会退还)
Gas Price每单位 Gas 的价格(单位:Gwei,1 Gwei = 10^9 Wei)
交易费用Gas Used × Gas Price(用户实际支付的 ETH)

EIP-1559 费用机制

EIP-1559(2021 年 London 升级引入)彻底改变了 Gas 定价方式:

EIP-1559 核心改变:

  • Base Fee:由协议根据上一个区块的 Gas 使用率自动调整。区块越满,Base Fee 越高。Base Fee 会被销毁(burn),不给验证者
  • Priority Fee(Tip):用户给验证者的额外小费,激励验证者优先打包自己的交易
  • maxFeePerGas:用户愿意为每单位 Gas 支付的最高价格
  • maxPriorityFeePerGas:用户愿意给验证者的最高小费
前端估算 Gas 费用
import { formatGwei, parseGwei } from 'viem';

// 获取当前 Base Fee 和建议的 Priority Fee
const block = await client.getBlock();
const baseFee = block.baseFeePerGas; // 当前 Base Fee

// 常见的前端 Gas 估算策略
const gasEstimate = {
// 慢速:Base Fee + 较低 Tip
slow: {
maxFeePerGas: baseFee * 2n, // 预留空间,防止 Base Fee 上涨
maxPriorityFeePerGas: parseGwei('0.1'),
},
// 标准:Base Fee + 中等 Tip
standard: {
maxFeePerGas: baseFee * 2n,
maxPriorityFeePerGas: parseGwei('1.5'),
},
// 快速:更高的 Tip,优先被打包
fast: {
maxFeePerGas: baseFee * 3n,
maxPriorityFeePerGas: parseGwei('3'),
},
};
常见 Gas 问题
  • Gas 估算不准:合约交互的 Gas 消耗可能因链上状态变化而不同,建议使用 eth_estimateGas 后再加 10-20% 的缓冲
  • 交易卡住:Gas Price 设置过低会导致交易长时间 pending,可以通过发送相同 nonce 但更高 Gas Price 的交易来替换(Speed Up)
  • Out of Gas:Gas Limit 设置过低会导致交易失败且 Gas 不退还,注意与用户余额不足区分

交易结构

每笔以太坊交易包含以下关键字段,前端 DApp 需要构造这些字段来发送交易:

以太坊交易结构(EIP-1559 Type 2)
interface Transaction {
// 基本字段
type: 2; // 交易类型:2 表示 EIP-1559
chainId: number; // 链 ID(以太坊主网 = 1,Sepolia = 11155111)
nonce: number; // 发送者账户的交易计数,防重放攻击
to: string | null; // 接收地址(null 表示部署合约)
value: bigint; // 转账金额(单位:Wei)
data: string; // 调用合约时的编码数据(ABI 编码)

// Gas 相关(EIP-1559)
maxFeePerGas: bigint; // 每单位 Gas 的最高价格
maxPriorityFeePerGas: bigint; // 给验证者的最高小费
gasLimit: bigint; // Gas 上限

// 签名字段(由钱包填充)
v: number;
r: string;
s: string;
}

关键字段解释:

  • nonce:保证交易顺序且防止重放攻击。前端需要注意,连续发送多笔交易时 nonce 必须递增,否则后续交易会 pending
  • to:为 null 时表示合约部署交易
  • data:调用合约函数时,该字段是函数签名和参数的 ABI 编码。纯 ETH 转账时为空(0x
  • chainId:防止在不同链上重放同一交易

交易生命周期

交易收据

交易被打包后,节点返回交易收据(Transaction Receipt),前端通过它判断交易结果:

解析交易收据
const receipt = await client.waitForTransactionReceipt({
hash: txHash,
});

// 关键字段
console.log(receipt.status); // 'success' 或 'reverted'
console.log(receipt.gasUsed); // 实际消耗的 Gas
console.log(receipt.effectiveGasPrice); // 实际 Gas 价格
console.log(receipt.blockNumber); // 被打包的区块高度
console.log(receipt.logs); // 交易产生的事件日志

区块确认与最终性

区块确认

交易被打包进区块后,并不意味着它是「最终的」。区块可能因为链重组(Reorg) 而被撤销。通常需要等待多个区块确认来降低风险:

场景建议确认数等待时间(PoS)
小额转账1-3 个区块12-36 秒
中等金额12 个区块~2.4 分钟
大额 / 交易所入账32 个区块~6.4 分钟
绝对最终性2 个 Epoch(64 个 Slot)~12.8 分钟

最终性(Finality)

以太坊 PoS 引入了确定性最终性:经过 2 个 Epoch(约 12.8 分钟)后,区块获得最终性,不可被回滚(除非 1/3 以上的验证者串谋攻击,这意味着巨额 ETH 被罚没)。

前端如何处理确认等待

前端 DApp 通常的做法是:交易提交后立即给用户「交易已提交」的反馈,同时在后台轮询确认数。可以使用 waitForTransactionReceipt 等 SDK 方法来等待交易上链,再更新最终状态。

Layer 2 概念简介

以太坊主网(Layer 1)吞吐量有限(~15 TPS),Gas 费用高昂。Layer 2 是建立在以太坊之上的扩容方案,通过在链下执行交易、将结果提交回 L1 来提升性能。

Rollup 方案对比

特性Optimistic RollupZK Rollup
原理乐观假设交易有效,出错后通过「欺诈证明」挑战每批交易附带零知识证明,数学保证正确性
代表项目Optimism、Arbitrum、BasezkSync、StarkNet、Scroll、Linea
提款时间7 天挑战期(可通过桥服务加速)几分钟(等待证明生成和验证)
兼容性与 EVM 高度兼容早期兼容性较差,zkEVM 逐步改善
Gas 费用较低(L1 的 ~5-10%)更低(长期趋势)
成熟度较成熟快速发展中
前端开发者需要知道的 L2 要点
  • L2 的 RPC 接口与 L1 基本一致,前端代码切换 L2 只需更改 chainId 和 RPC URL
  • 需要处理跨链桥的 UI 逻辑(L1 ↔ L2 资产转移)
  • L2 上的交易确认更快、Gas 更低,但最终性仍依赖 L1 确认
  • 使用 viem / wagmi 时,通过配置不同的 chain 即可切换网络

常见面试问题

Q1: 区块链为什么不可篡改?

答案

区块链的不可篡改性源于哈希链接结构共识机制

  1. 哈希链接:每个区块头包含上一个区块头的哈希(parentHash)。篡改任一区块的数据会导致其哈希变化,从而使后续所有区块的 parentHash 失效,需要重新计算整条链
  2. 共识机制:在 PoS 中,攻击者需要控制全网 2/3 以上的质押 ETH 才能篡改已最终确认的区块,这在经济上几乎不可行
  3. 分布式验证:全球数千个节点同时存储和验证数据,单点篡改会被其他节点拒绝

Q2: EOA 和合约账户的区别是什么?

答案

核心区别在于控制方式功能

  • EOA 由私钥控制,可以主动发起交易;合约账户由代码控制,只能被动响应调用
  • EOA 没有代码和存储空间;合约账户有 EVM 字节码和独立的存储
  • 所有链上操作的源头必须是 EOA 发起的交易,合约账户无法自己发起交易

前端开发中,可以通过 eth_getCode 判断一个地址是 EOA 还是合约:

判断账户类型
const code = await client.getCode({ address: '0x...' });
const isContract = code !== undefined && code !== '0x';

Q3: 什么是 Gas?为什么需要 Gas 机制?

答案

Gas 是衡量 EVM 操作计算成本的单位。需要 Gas 机制的原因:

  1. 防止滥用:没有成本约束,攻击者可以提交无限循环的恶意合约,耗尽网络资源
  2. 资源定价:不同操作消耗不同的计算资源,Gas 机制让用户为实际使用的资源付费
  3. 激励验证者:Gas 费用中的 Priority Fee 是验证者的收入来源

Q4: 解释 EIP-1559 的 Base Fee 和 Priority Fee

答案

EIP-1559 将 Gas 费用分为两部分:

  • Base Fee:由协议根据网络拥堵程度自动调整的基础费用。当上一区块 Gas 使用超过 50% 目标时,Base Fee 上涨(最多 12.5%);反之下降。Base Fee 会被销毁,不给验证者
  • Priority Fee(Tip):用户额外支付给验证者的小费,用于激励优先打包。网络繁忙时需要更高的 Tip

用户设置 maxFeePerGas 作为最高支付上限,实际费用 = min(maxFeePerGas, baseFee + maxPriorityFeePerGas),多余部分退还。

Q5: 以太坊的 PoW 和 PoS 有什么区别?The Merge 是什么?

答案

  • PoW:矿工消耗算力竞争出块权,能耗高、出块时间不稳定
  • PoS:验证者质押 ETH,被随机选中出块,能耗极低、出块时间固定 12 秒
  • The Merge(2022 年 9 月)是以太坊从 PoW 切换到 PoS 的里程碑事件,将能耗降低了约 99.95%,并引入了确定性最终性

对前端的影响:出块时间固定化、block.difficulty 被弃用、区块最终性模型改变。

Q6: 交易的 nonce 是什么?有什么作用?

答案

nonce 是该账户发出的交易计数(从 0 开始)。作用:

  1. 保证交易顺序:节点按 nonce 递增顺序处理交易。nonce=3 的交易必须在 nonce=2 之后执行
  2. 防止重放攻击:同一 nonce 只能执行一次,防止同一笔交易被重复执行
  3. 交易替换:发送相同 nonce 但更高 Gas Price 的交易可以替换 pending 中的交易(Speed Up / Cancel)

前端常见问题:连续快速发送多笔交易时,需要手动管理 nonce 递增,否则会出现交易卡住。

Q7: 什么是 Merkle Tree?前端开发中有哪些应用场景?

答案

Merkle Tree 是一种哈希二叉树,叶节点是数据的哈希,非叶节点是其子节点哈希的组合哈希。只需提供一条从叶到根的哈希路径(Merkle Proof)即可验证某个数据是否在树中。

前端应用场景:

  • NFT 白名单:将白名单地址构建成 Merkle Tree,链上只存储 Root Hash,用户 Mint 时提交 Merkle Proof 验证资格
  • 空投验证:大规模空投时使用 Merkle Distributor 合约,用户凭 Proof 领取
  • SPV 轻客户端:验证某笔交易是否在某个区块中,无需下载完整区块

Q8: 什么是 EVM?它与前端的关系是什么?

答案

EVM 是以太坊的虚拟执行环境,所有节点运行同一份 EVM 代码,保证执行结果的确定性。

与前端的关系:

  • 前端通过 ABI 编码向 EVM 发送调用指令(data 字段)
  • 读操作(eth_call)在本地 EVM 模拟执行,不消耗 Gas
  • 写操作(eth_sendTransaction)由验证者在 EVM 中执行,消耗 Gas
  • 合约的 Events/Logs 由 EVM 执行过程中产生,前端通过 eth_getLogs 或 WebSocket 订阅获取

Q9: Layer 2 是什么?Optimistic Rollup 和 ZK Rollup 有什么区别?

答案

Layer 2 是以太坊的扩容方案,在链下执行交易,将结果批量提交到 L1:

  • Optimistic Rollup:乐观假设交易正确,任何人可在 7 天挑战期内提交欺诈证明来撤销无效交易。优点是 EVM 兼容性好,缺点是提款时间长
  • ZK Rollup:每批交易附带数学上的零知识证明,无需信任假设。优点是安全性更强、提款更快,缺点是证明生成复杂、早期 EVM 兼容性差

对前端来说,L2 的 JSON-RPC 接口与 L1 基本一致,代码迁移成本很低。

Q10: 前端如何估算交易的 Gas 费用?

答案

Gas 估算流程
// 1. 估算 Gas Limit
const gasLimit = await client.estimateGas({
account: userAddress,
to: contractAddress,
data: encodedFunctionData,
});

// 2. 获取当前 Gas 价格建议
const gasPrice = await client.estimateFeesPerGas();
// 返回 { maxFeePerGas, maxPriorityFeePerGas }

// 3. 计算预估费用(单位:Wei)
const estimatedCost = gasLimit * gasPrice.maxFeePerGas;

// 4. 加上缓冲(推荐 10-20%),防止链上状态变化导致 Gas 不足
const safeGasLimit = gasLimit * 120n / 100n;

最佳实践:使用 eth_estimateGas 获取基准值后加缓冲,同时展示预估费用给用户确认。

Q11: 交易的 data 字段里存了什么?

答案

data 字段包含函数选择器(4 字节)+ ABI 编码的参数

  • 函数选择器 = 函数签名的 keccak256 哈希的前 4 字节,如 transfer(address,uint256)0xa9059cbb
  • 参数按 ABI 编码规则拼接在后面,每个参数占 32 字节

纯 ETH 转账时 data 为空(0x)。前端使用 viem 的 encodeFunctionData 或 ethers 的 interface.encodeFunctionData 来生成。

Q12: 什么是区块链的最终性(Finality)?以太坊 PoS 如何实现?

答案

最终性是指交易一旦确认就绝对不可被回滚的保证:

  • PoW 时代:只有概率性最终性,随着后续区块增多,回滚的概率指数下降但永不为零
  • PoS 时代:以太坊引入了确定性最终性。每 32 个 Slot(约 6.4 分钟)组成一个 Epoch,经过 2 个 Epoch 的验证者投票确认后,区块获得最终性。回滚已最终确认的区块需要至少 1/3 的验证者被罚没质押的 ETH

前端在处理大额交易时,应等待最终性确认再更新 UI。

Q13: chainId 的作用是什么?前端开发中需要注意什么?

答案

chainId 用于标识不同的区块链网络,防止跨链重放攻击(在一条链上签名的交易被拿到另一条链上执行)。

常见 chainId:以太坊主网 = 1,Sepolia 测试网 = 11155111,Arbitrum = 42161,Base = 8453。

前端注意事项:

  • 必须检测用户钱包当前连接的 chainId 是否正确
  • 提供切换网络功能(wallet_switchEthereumChain
  • 监听 chainChanged 事件,在用户手动切换网络时更新 DApp 状态

相关链接