01 · Separate the layers
先拆开四个经常混在一起的东西
网络、客户端、虚拟机、合约不是四种说法,而是四个层次。 先分清“谁保存规则、谁实现规则、谁被执行、谁让历史收敛”。
如果把以太坊说成一台计算机,最容易产生的误会是:世界上真的有一台叫“EVM”的服务器。 实际上,EVM 是一套抽象机器的协议语义;许多独立执行客户端分别实现它, 在各自机器上重放同一批交易。[1]
智能合约则是存放在以太坊状态中的程序:它有可执行代码,也可以拥有持久状态,并位于某个地址。 用户提交交易请求调用它;合约也可以在一次交易内部向其他合约发出消息调用。 它不是“会思考的合同”,也不会脱离交易自己醒来。[2]
Interactive · Architecture lens
点选组件,看它负责什么、不负责什么
当前焦点
智能合约:被执行的规则
链上真正保存并执行的是编译后的 EVM 字节码。它可以读取输入、检查条件、调用其他合约, 并在权限与 Gas 允许时修改自己的存储或转移资产。
不负责:主动发起顶层交易、决定自己何时运行、选择哪一个区块成为规范历史。
02 · State transition
以太坊不只记账,它按规则改变一整个世界状态
余额只是状态的一部分。合约代码、合约存储、账户 nonce 等共同构成执行层状态; 每笔有效交易都是一次受约束的状态转换。
可以把执行抽象成一个函数: 新状态 σ′ = Υ(旧状态 σ, 交易 T)。 这个记号来自以太坊形式化规范对交易状态转换的表达。[9]
这里的“状态”不是一张余额表,而是所有相关账户当时的余额、nonce、代码承诺与存储承诺。 一笔调用还会产生收据、Gas 使用量和日志;这些不是随意的旁白,而是节点可重复验证的协议结果。
区块内交易必须按确定顺序逐笔折叠: σ₁ = Υ(σ₀,T₀), σ₂ = Υ(σ₁,T₁),依此类推。 相同交易集合换一个顺序,前置余额、nonce、合约价格或库存就可能不同,最终状态也可能随之改变。
Interactive · State lab
同一个 setScore(42),成功、回滚与本地模拟有什么不同?
“执行失败就什么都没发生”并不准确。若顶层交易已经上链但 EVM 执行回滚,
合约状态写入会撤销,然而发送者的 nonce 已被使用,已经消耗的计算也仍需付费。
如果只是通过 RPC 做 eth_call,节点在本地模拟,不进入区块,也不会留下共享状态变化。
还要区别“进入前即无效”:签名、nonce 或余额等基本有效性不满足的交易,不能作为有效交易被区块执行,也不会产生链上 receipt。
03 · From source to bytecode
Solidity 源码不会直接在链上运行
人写高级语言,编译器产出字节码和 ABI;部署交易安装程序,调用交易只携带地址、数值与一串编码后的字节。
EVM 不理解变量名、注释或“这段代码的商业意图”。它理解的是字节码中的操作码。 Solidity、Vyper 等语言必须先编译,才能部署给 EVM 执行。[3]
ABI(应用二进制接口)则像一份“如何把人类函数调用编码成字节”的说明书。 对典型 Solidity 外部函数调用,calldata 前 4 字节是函数选择器, 后面是按类型编码的参数。选择器取函数规范签名 Keccak-256 哈希的前 4 字节。[5]
Interactive · Lifecycle
部署是在“安装程序”,调用是在“给程序输入”
编写源码
开发者用高级语言表达状态和规则。
contract Score {
uint256 score;
function setScore(uint256 next) external {
score = next;
}
}
编译
编译器产出创建字节码、运行时字节码与 ABI。
creation bytecode
runtime bytecode
ABI
source ≠ bytecode
发送部署交易
to 为空;data 携带创建代码和构造参数。
to: null
data: 0x6080…
value: 0
gasLimit: …
创建合约账户
初始化代码运行,其返回值成为地址上的运行时字节码。
address: 0xScore…
code: 0x6080…
storage[0]: 0
04 · Inside the EVM
EVM 执行时,数据住在哪里?
“变量”在源码里看起来相似,到了 EVM 却可能属于完全不同的空间。 生命周期、可写性和 Gas 成本差异巨大。
EVM 是 256 位字长的栈式虚拟机,栈最大深度为 1024 项。 每次消息调用还有临时 memory;每个合约账户拥有持久 storage; 交易输入以 calldata 进入。现代 EVM 还提供仅在一笔交易内存活的 transient storage。[1]
初学者不需要马上背操作码,但必须先建立“数据寿命”心智模型: 一次操作、一次调用、一笔交易、跨交易持久化,是四个不同时间边界。
Interactive · EVM workspace
切换数据空间,观察寿命与边界
OPERATION WORKSPACE
Stack:操作码手边的计算栈
EVM 的大多数指令从栈顶取值、计算,再把结果压回栈顶。栈元素是 256 位字, 最大深度 1024;它适合当前执行帧里的即时运算,不负责跨调用保存业务状态。
以 score = 42 为例:42 可能先从 calldata 解码到栈或 memory,
最终由存储写入指令改变合约 storage。交易成功后,持久存储变化进入新世界状态;
如果调用回滚,当前失败作用域的这些写入不会提交。[6]
05 · One call, end to end
一笔 setScore(42) 如何穿过以太坊?
把钱包、交易池、区块提议、执行、验证、状态根和最终性接起来。 这条链一旦通了,前面所有名词才真正成为架构。
顶层交易由可授权交易的账户签名并广播。交易包含目标地址、数值、输入数据、nonce 与费用上限等字段; 当目标地址有可执行代码时,执行客户端会以 calldata 为输入启动相应代码。[4]
Interactive · Dual-lane journey
逐步查看:谁在算,谁在决定顺序
STEP 01 · WALLET / ABI
钱包把“setScore(42)”翻译成机器输入
尚未改变链上状态
钱包根据 ABI 生成 calldata。用户看到“调用函数”,网络看到的是一组带类型语义的字节。 仅仅点击按钮不会自动改链;下一步还需要账户授权并广播交易。
边界:钱包是界面与签名工具,不是共识权威;它可以把意图显示错,所以签名前必须核对实际交易字段。06 · Execution ≠ consensus
执行层回答“结果对不对”,共识层回答“哪段历史算数”
两层必须协作,但不能用一句“验证者执行并确认”把职责糊在一起。 分清它们,是理解合并后以太坊架构的关键。
给定同一个前状态与同一组有序交易,执行层应当得出唯一后状态。 但网络可能在短时间看到不同候选区块;共识层需要用提议、证明、分叉选择与最终性规则让节点收敛到规范历史。 两类客户端通过 Engine API 交换执行载荷与有效性结论。[12][13]
因而,“执行正确”是一个必要条件,却不等于“这个候选区块已经成为最终历史”。 反过来,共识权重也不能投票把错误计算变成正确计算:无效执行载荷应被合规节点拒绝。
Comparison · Two layers
同一节点软件栈里的两条判断链
07 · Determinism & offchain boundary
为什么合约不能直接请求天气网站?
所有诚实节点必须对同一输入复现同一输出。 任何可能因地点、时间或服务器响应而不同的外部读取,都会破坏这条前提。
EVM 的关键不是“算得快”,而是可重复、可验证。 节点使用协议允许的前状态、交易与区块上下文计算;不同实现若产生不同结果,就会造成共识级问题。
因此合约不能像普通后端那样在执行中直接发 HTTP 请求。节点 A 可能得到晴天,节点 B 可能超时, 节点 C 可能被不同 CDN 返回值命中。以太坊无法从这些答案中确定唯一状态。 若需要链外事实,通常由预言机或其他参与者把数据作为可验证的链上输入提交;合约再按规则消费它。[2]
Interactive · Re-execution
相同输入、错误实现与链外分歧
链外世界
天气、价格、比赛结果
事实可能由不同来源、不同时间与不同权限观察;HTTP 响应本身不属于 EVM 的确定性协议输入。
交易 / 消息
→
链上世界
可复算的状态转换
数据进入链上后,合约验证发送者、格式、时效或聚合规则,再以同一输入执行确定性逻辑。
08 · Gas & atomicity
Gas 给计算设边界,回滚给组合调用设安全语义
EVM 允许通用程序,却不能允许无限工作。 每条操作按协议计量;调用成功就提交,失败作用域的状态变化则撤销。
Gas 是计算与资源使用的计量单位,Gas fee 才是用户最终支付的费用。 可以先记住:执行费 ≈ gas used × effective gas price。 Gas limit 则给一笔交易最多可消耗的工作量设置上限。
如果执行耗尽 Gas,当前执行失败并回滚相应状态变化;已经消耗的 Gas 不会因为“没有业务结果”而免费。
REVERT 指令允许合约主动停止、回滚当前失败作用域并返回错误数据,
而不会像耗尽 Gas 那样自动吃掉该调用剩余的全部 Gas。[7][14]
Interactive · Call tree
成功、未捕获回滚、捕获子调用失败
A 调用 B,B 成功返回,A 继续执行;顶层交易成功时,整个调用树中未回滚的状态写入一起提交。
09 · Read versus write
“调用合约”可能只是本地模拟,也可能真正改链
前端里的一个按钮,背后可能走两条完全不同的路径。 是否签名、是否进区块、是否付费、是否留下状态,是判断关键。
读取 getScore() 常由节点通过 eth_call 在指定区块状态上本地执行;
它不创建链上交易,用户不为这次 RPC 模拟支付费用。写入 setScore(42) 则需要授权交易、等待被打包并支付执行费用。
| 判断项 | 本地读取 / eth_call | 状态写入 / transaction |
|---|---|---|
| 需要账户签名? | 通常不需要;可以带模拟的 from | 需要有效授权,顶层交易有发送者 |
| 进入交易池与区块? | 不进入,只由被请求节点本地执行 | 广播后等待提议者纳入候选区块 |
| 用户付 Gas fee? | 不向链支付;服务商仍承担计算资源 | 按链上实际 Gas 使用与有效价格结算 |
| 改变共享状态? | 不会;返回值是对某个状态的模拟结果 | 成功且进入规范历史后产生持久状态变化 |
| 结果会不会过期? | 会;下一块或并发交易可能改变读取前提 | 一旦执行,结果属于该区块上下文;最终性再增强历史确定性 |
Solidity 的 view / pure 描述函数对状态的约束,不等于“在任何场景都没有 Gas”。
从前端以 eth_call 模拟时用户不付链上费用;若另一个合约在一笔真实交易中调用这些函数,
相关 EVM 指令仍消耗该交易的 Gas。[4]
普通 Solidity 函数的返回值不会自动永久写进交易 receipt。返回数据在执行期间交给调用者;
链下应用可通过 eth_call 取得模拟返回值,或在真实交易后查看 receipt 中的 status 与 logs。
需要让链下索引器长期观察的信息,通常由合约明确发出事件日志。
10 · Boundaries & misconceptions
六个误区,决定你是否真的理解了“世界计算机”
口号往往省略边界。把下面六句话改准确, 你就已经拥有分析钱包、DApp、合约与节点问题的基础框架。
误区 01 · “EVM 是一台全球服务器”
EVM 是共同执行语义,不是单点机器
多个执行客户端实现同一协议,在独立节点上复算。任何一台机器都不是全网结果的唯一发布者。
误区 02 · “合约会自动运行”
合约必须处在某笔交易的调用树里
EOA 或协议允许的账户授权发起顶层交易;合约只能在被调用后继续调用其他合约。
误区 03 · “全世界每个人都执行每笔交易”
执行节点复算,普通用户设备未必复算
全执行节点验证状态转换;轻客户端、托管钱包和普通浏览器可能依赖证明或 RPC,而非本地完整执行。
误区 04 · “链上跑的是 Solidity”
EVM 执行的是部署后的字节码
源码与 ABI 帮助人和工具理解;只有重编译匹配,才能把公开源码与实际字节码可靠对应。
误区 05 · “交易回滚就完全没成本”
状态可回滚,资源消耗与顶层 nonce 不倒退
失败交易仍占区块空间、消耗计算;回滚保护状态一致性,不是免费撤销按钮。
误区 06 · “代码就是法律,没人能改”
要检查代理、管理员、预言机和治理边界
某个地址的运行时代码通常不可原地改写,但系统可通过代理等模式把逻辑指向新实现;权限结构才决定实际控制面。
Summary · Mental model
从意图到共同历史,只保留五个动作
编码意图
ABI 把函数与参数变成 calldata。
授权请求
账户签名交易,声明 nonce 与资源上限。
确定性执行
EVM 解释字节码,读取并尝试改变状态。
独立复算
执行节点验证同一后状态、收据与 Gas。
历史收敛
共识选择规范链,最终性增强不可逆确定性。
11 · Understanding check
不用背术语,检查你能否解释因果
每题只选一个最准确答案。答完后,尝试不看页面说出: “为什么相同字节码能在没有中央服务器时形成共同状态?”
1. EVM 最准确的定位是什么?
EVM 是协议定义的执行模型;客户端可以用不同语言实现,但对有效输入必须产生兼容结果。
2. 调用 setScore(42) 的 calldata 前 4 字节通常表达什么?
典型 Solidity ABI 调用以 4 字节函数选择器开头,后面跟按 ABI 编码的参数。
3. 一笔已上链交易执行 REVERT 后,哪项说法正确?
回滚保护状态一致性;它不会否认节点已实际完成的计算,也不会让顶层交易 nonce 重用。
4. 为什么合约不能在执行中直接请求任意天气 API?
链外数据必须通过某种可进入共识的输入机制提交;预言机解决输入与信任,而非取消确定性要求。
5. 执行层与共识层的分工,哪项最准确?
共识不能把无效执行投票变有效;执行也不能独自解决竞争区块的规范顺序。
12 · Glossary & primary sources
把术语钉在正确层级上
下面不是背诵表,而是一组最小定义。遇到新概念时, 先问它属于输入、执行、状态,还是共识。
- EVM
- Ethereum Virtual Machine。协议定义的确定性执行环境;执行客户端实现它,用于解释 EVM 字节码。
- 智能合约
- 部署在以太坊地址上的程序与相关状态。它由交易或消息调用触发,而不是独立进程。
bytecode- EVM 原生执行的字节序列。高级语言源码需要编译为创建字节码与运行时字节码。
calldata- 消息调用的只读输入字节;典型 ABI 调用包含 4 字节函数选择器和编码参数。
storage- 账户关联的持久键值存储;成功交易中的写入会影响后续状态,修改通常比临时数据操作昂贵。
- 状态转换
- 把前状态与有效交易按协议规则映射为后状态的过程,可抽象为 σ′ = Υ(σ, T)。
- Gas
- EVM 工作量与资源使用的计量单位。Gas fee 是 Gas 使用量与每单位有效价格共同形成的 ETH 费用。
REVERT- 停止当前执行并回滚失败作用域状态变化、返回错误数据的 EVM 指令;已消耗 Gas 不会倒退。
- 执行层
- 处理交易有效性、EVM 执行、状态、收据和执行载荷的协议与客户端职责集合。
- 共识层
- 通过 PoS 提议、证明、分叉选择与最终性规则,让节点对规范区块历史收敛。
一手资料
- ethereum.org · Ethereum Virtual Machine (EVM) — EVM 的状态机定位、栈式执行、memory、storage 与 transient storage。
- ethereum.org · Introduction to smart contracts — 合约的代码与状态、调用方式、可组合性和链外数据边界。
- ethereum.org · Compiling smart contracts — 高级语言源码如何变成 EVM 可执行字节码与操作码。
- ethereum.org · Transactions — 交易字段、calldata、合约部署/调用、Gas 与交易生命周期。
- Solidity documentation · Contract ABI Specification — 4 字节函数选择器与参数编码的规范。
- Solidity documentation · Introduction to Smart Contracts — storage、transient storage、memory、stack、交易与消息调用。
- EIP-140 · REVERT instruction — 回滚状态变化、返回错误数据以及剩余 Gas 语义。
- EIP-7702 · Set Code for EOAs — 账户代码委托指示器、Type 4 交易与传统 EOA/合约边界的变化。
- Ethereum Yellow Paper — 交易状态转换函数 Υ 的形式化表达;用于理解模型,当前升级细节应以活跃执行规范为准。
- Ethereum Execution Layer Specifications — 跟随网络升级维护的执行层规范与测试基准。
- ethereum.org · Smart contract composability — 合约作为公开可组合组件的模型与边界。
- Ethereum Execution APIs · Engine API — 合并后共识客户端与执行客户端交换载荷、构建请求和有效性结论的接口规范。
- Ethereum Consensus Specifications — 共识状态转换、分叉选择、验证者职责与最终性的活跃规范。
- ethereum.org · Gas and fees — Gas 计量、费用、Gas limit 与执行资源边界。
- EIP-6780 · SELFDESTRUCT only in same transaction — Cancun 以后 SELFDESTRUCT 对既有合约代码与存储的现行语义。
核对日期:2026-07-25。协议会继续升级;涉及具体操作码、Gas 定价、交易类型与客户端行为时,应回到当前执行规范和对应 EIP。