Ethereum learning path · 04.05

一个地址,
究竟由谁控制?从 EOA、合约账户到可编程账户

把“地址、账户、钱包、代码”四个常被混用的词彻底分开, 再看经典二分法如何被 EIP-7702 与 ERC-4337 更新。

  • 04 · 05 账户模型总装课
  • 52 MIN 阅读与实验
  • 0 → 深入 无需编程基础

The thesis

账户不是钱包,也不是“装币的盒子”。它是世界状态中由地址索引的一条记录; 谁能让这条记录改变,才是账户模型真正回答的问题。

01 · Orientation

先把四个词分开

地址、账户、钱包、控制权处在四个不同层次。

第四章收束 · 经典模型为主,现代边界校准为辅

当钱包界面显示“账户 1:0x7A…19,余额 3.2 ETH”时,一行 UI 把四件事压在了一起:一个地址、一条链上账户记录、 一个帮你签名和发送请求的钱包,以及决定请求是否被授权的 控制规则。不先拆开它们,后面所有概念都会粘在一起。

一句定义

在执行层的经典模型里,世界状态可以先想成一张巨大映射: 用 20 字节地址查找账户记录;记录里保存 nonce、ETH 余额、存储根和代码哈希。[1]

σ[address] → ( nonce, balance, storageRoot, codeHash )
σ′ = Υ( σ, ordered transactions ) σ 是旧世界状态,σ′ 是新世界状态。Υ 表示协议规定的状态转换规则。 地址只是索引;“这个变化是否被允许”还要看签名、代码和交易上下文。

四层心智模型

01 · ADDRESS

地址是索引

像数据库键,用来定位状态与接收消息。它不是用户名,也不自动说明背后是谁。

02 · ACCOUNT

账户是状态记录

协议关心的是 nonce、原生 ETH 余额、代码承诺和持久存储承诺。

03 · WALLET

钱包是交互工具

管理密钥或智能账户权限、构造请求、展示资产;钱包不等于链上的账户。

04 · AUTHORITY

控制权是一套规则

经典 EOA 看有效签名,合约账户看代码;现代智能账户可以组合多种授权策略。

这也解释了一个常见句子:“币在我的钱包里”只是方便表达。 ETH 余额保存在以太坊状态中,ERC-20 余额通常保存在代币合约的 balances[address] 映射里;钱包读取这些状态并替你组织授权请求。 你真正保管的是能满足控制规则的秘密或凭证。

本课边界

下一章会专门解释私钥、公钥、地址与助记词;第六章会拆交易字段和传播流程; 第十一章会拆状态树。本课只引入足够细节,把账户模型装完整。

02 · State model

为什么以太坊选择账户模型?

UTXO 追踪“还没花掉的输出”,账户模型维护“当前状态”。

想象两种记账方式。第一种把每张未使用的现金券单独编号:付款时销毁旧券, 再创建收款券与找零券。第二种为每个人维护一行余额:付款时直接减少 Alice, 增加 Bob。前者接近比特币的 UTXO 模型,后者接近以太坊的账户模型。

Interactive · 01

同一笔 2 ETH 支付,两种状态表示

点击“执行支付”,观察被消费的输出与被原地更新的余额。

UTXO · 未花费输出集合

花掉整张旧输出,再产生收款输出与找零输出;不是把某张券“改小”。

#A7 · Alice3.0 ETH
#A8 · Alice1.5 ETH
#B0 · Bob0.4 ETH
#B1 · Bob · 新建2.0 ETH
#A9 · Alice · 找零1.0 ETH

ACCOUNT · 地址到账户状态

同一全局状态里的余额字段被更新;交易历史仍然保留,并不是抹掉旧历史。

0xAlice4.5 ETH
0xBob0.4 ETH
0xVault12.0 ETH

初始 Alice 在 UTXO 侧拥有两张独立输出;在账户侧拥有一条 4.5 ETH 余额记录。

UTXO 与账户模型对照
问题UTXO 模型账户模型
当前状态是什么所有尚未被消费的输出集合地址到账户记录与合约存储的映射
支付如何发生消费旧输出,创建新输出验证后更新相关账户字段
找零如何表示通常创建新的找零输出发送者剩余余额留在同一账户
复杂程序状态通常要把状态附着在输出与脚本设计上合约地址天然拥有可持续更新的存储空间
并行分析输入集合明确,冲突通常更局部多个调用可能触碰共享状态,需要处理依赖顺序

账户模型给以太坊带来了什么?

最大收益不是“看起来像银行余额”,而是复杂状态的连续性。 一个借贷合约可以在固定地址下持续维护抵押率、债务、利率索引和清算参数; 下一笔调用直接读取上一次调用留下的状态。多份合约还能在同一笔交易中互相调用, 形成可组合应用。

代价也很真实:共享可变状态让执行顺序重要。两笔交易分别看都有效, 换序后可能得到不同结果;因此账户模型不仅要回答“余额多少”,还要用 nonce、 Gas、确定性执行与共识顺序共同约束状态推进。

不要误解“更新”

账户模型更新的是当前世界状态。区块和交易历史仍以可验证方式保留, 所以节点可以从较早状态按顺序重放交易,重新计算后来的状态。

03 · Account record

账户记录里,究竟存了什么?

地址不是记录的一部分;它是找到记录的键。

初学者常把账户想成一张“姓名、密码、余额”表。协议并不认识姓名,也不保存密码。 执行层关注四个字段:nonce、balance、storageRoot、codeHash。 这四个字段既能表示普通 EOA,也能表示拥有代码和存储的合约账户。

四个字段逐一拆开

nonce 是顺序与唯一性的计数器。对经典 EOA,可把它理解为已发出交易的顺序号; 网络不会在同一账户状态下接受两笔相同 nonce 的交易都成功执行。对合约账户, nonce 还参与跟踪合约创建。它不是全网统一区块高度,也不是钱包随意生成的备注。

balance 以 wei 记录原生 ETH,1 ETH = 1018 wei。 它不自动包括 USDC、WETH 或 NFT。那些资产的“谁拥有多少”通常写在各自合约存储中; 区块浏览器和钱包只是把多个合约的查询结果汇总展示。

storageRoot 是该账户持久存储内容的密码学承诺。你不需要现在掌握 trie, 只要知道它让一份可能很大的键值存储被一个固定大小的根值承诺。 合约执行改变存储槽后,这个根也会改变。

codeHash 承诺该账户的 EVM 代码。收到消息调用时,执行客户端据此取得代码并执行。 经典 EOA 的代码为空;传统合约账户拥有运行时字节码。EIP-7702 会在这里放入一个特殊 “委托指示器”,所以“有代码就一定是传统合约”已不再绝对。[3]

精度提醒

“任意 0x 地址都已经有一个账户”也不严谨。地址空间巨大,某个地址可能尚无状态记录; 协议还区分不存在、空账户与非空账户。入门时先抓住“地址是索引”,不要把每个可能地址想成预先建好的文件夹。

04 · Authority

两类经典账户,差异在控制规则

两者都能拥有地址和 ETH;真正的分界是如何触发行为。

Externally owned account

  • 控制:满足协议要求的数字签名。
  • 起点:经典模型中可以主动发起顶层交易。
  • 创建:离线生成密钥即可得到地址,不需要链上部署。
  • 行为:若没有委托代码,收到普通转账不会运行自定义程序。
  • 风险:私钥泄露通常意味着攻击者获得同等控制力。

Contract account

  • 控制:部署在地址上的代码与其持久状态。
  • 起点:传统模型中不能凭空发起顶层交易,只能被调用后继续发送消息。
  • 创建:部署执行消耗 Gas,并产生运行时代码和地址。
  • 行为:收到调用时可转账、改存储、调用其他合约或创建合约。
  • 风险:代码会忠实执行,包括漏洞、错误权限与恶意逻辑。

“合约账户没有私钥”并不等于“没人能管理它”。合约代码可以规定: 只有某个 EOA 签名者、多个管理员、DAO 投票或时间锁满足条件时才能执行某函数。 这些私钥控制的是调用权限,而不是合约地址天然对应的一把私钥。

反过来,“EOA 由私钥控制”也不代表私钥被存进链上账户。 私钥永远不应公开;节点通过签名恢复或验证授权者,再检查 nonce、余额和交易规则。 密钥与地址的数学关系会在下一章完整展开。

两类账户都能做什么?

经典 EOA 与传统合约账户能力对照
能力经典 EOA传统合约账户
拥有地址
持有原生 ETH
成为 ERC-20 / NFT 所有者是,记录在资产合约中是,记录在资产合约中
发起协议顶层交易是,由签名授权经典模型下不是
收到调用后执行自定义代码经典模型下不是
自定义多签、限额、恢复原生规则很有限可以由代码定义
最稳固的记忆法

不要只背“EOA 无代码、合约有代码”。先问: 什么证据允许它发起请求?收到消息后,是否有代码决定下一步? 这个问法在 EIP-7702 之后仍然有效。

05 · State transition

一次调用,改变的从来不只一个账户

用 Alice 向 Vault 存入 1 ETH,看账户模型如何原子推进。

Alice 在钱包中确认 Vault.deposit(),看起来只是点了一次按钮。 对执行层而言,这是一条有序状态转换:验证发送者、消费 nonce、计费、 转移 ETH、运行 Vault 代码、更新合约存储,最后把多处变化共同写进新世界状态。

Interactive · 03

一笔存款调用的状态切片

费用用 0.002 ETH 的教学示例表示,不代表实时费率。

Alice · EOA0x7A4c…A219

nonce
7
ETH balance
5.000 ETH
authorization
尚未检查

Vault · Contract0xB41d…91C0

ETH balance
12.000 ETH
credit[Alice]
1.000 ETH
code
deposit()

World stateshared execution state

stateRoot
0x8b7a…44e1
result
等待输入
gas used
0

调用前 Alice 的下一笔交易应使用 nonce 7;Vault 记录 Alice 已有 1 ETH 额度。

ATOMICITY

成功时,转账与存储更新一起生效;执行回滚时,调用造成的状态变化一起撤销。 但已经执行的计算仍消耗 Gas,顶层交易 nonce 也会被消费。[7]

为什么一个按钮会触碰多条记录?

Alice 的 EOA 要防止重放和承担费用,所以 nonce 与余额会变化; Vault 收到 1 ETH,所以原生余额变化;Vault 还要记住这 1 ETH 属于 Alice 的内部额度, 所以存储根变化;这些变化最终共同反映在新的 stateRoot 中。

注意“Vault 内部记了 Alice 1 ETH”与“Vault 地址的原生 ETH 余额增加 1 ETH” 是两层状态。前者是应用会计规则,后者是协议原生余额。合约如果写错内部会计, 协议不会替它猜测真实意图,只会确定性执行代码。

一笔顶层交易还可以触发多层内部消息调用。合约 A 调合约 B,B 再调 C, 这些内部消息不是三笔新的顶层签名交易,却都发生在同一个原子执行上下文里。 这正是以太坊“可组合性”的技术基础,也是重入、权限和 Gas 风险的来源。

先不展开

本实验隐藏了费用预扣、退款、Base Fee 销毁、收据与日志等中间细节。 第六章会沿一笔真实交易逐字段拆解,第七章再专门讲 Gas。

06 · EIP-7702

经典二分法,为什么不再够用?

Pectra 之后,EOA 可以在自己的账户上设置代码委托指示器。

经典教材用一句话区分账户:“EOA 没有代码,合约账户有代码。” 这曾经非常好用,但 EIP-7702 已经让它变成入门近似。 新的 Set Code 交易类型允许 EOA 签署授权,把一个特殊委托指示器写入自己的代码字段。 后续对该 EOA 的执行会加载被指向的代码。[3]

01 · AUTHORITY

EOA 签署授权

授权元组包含 chain_id、目标实现地址和 authority nonce。chain_id 非零时绑定该链;为 0 时可跨链使用。

02 · INDICATOR

写入委托指示器

账户代码成为 23 字节的 0xef0100 || address 指针,不是复制整份实现代码。

03 · RESOLVE

解析目标代码

调用触及该 EOA 时,执行客户端跟随一次指针,取得目标地址的代码。

04 · CONTEXT

在 EOA 上下文执行

代码逻辑来自目标地址,但余额、地址与存储上下文属于这个 EOA。

CODE COMES FROM

委托实现地址

像借来一套经过审计的钱包逻辑:批量调用、赞助 Gas、会话密钥或恢复规则都可由代码提供。

STATE STAYS AT

原 EOA 地址

资产地址不必迁移;委托代码在 authority 的执行上下文中读写,因此存储布局与升级安全至关重要。

它没有把 EOA 简单“变成合约账户”

更准确的说法是:协议允许某类带有效委托指示器的 EOA 保持交易发起能力, 同时在被执行时表现出可编程逻辑。授权可以被后续授权更换或清除;签名密钥仍承担关键控制角色。 委托设置后会跨交易保留,直到以后被替换或清除,并非只在当前调用中临时生效。 因此它是对账户行为边界的扩展,不是删除 EOA,也不是普通合约部署。

外层 Set Code 交易的发送者还可以与被授权的 EOA 不同,因此赞助者能够代付这次上链费用。 另一个反直觉细节是:有效授权元组在调用执行前被处理;即使后面的调用发生 REVERT,已经写入的委托指示器以及对应的 authority nonce 增量也不会随执行结果回滚。 所以不能用“交易失败了”推断账户没有发生委托变化。[3]

经典账户、委托 EOA 与 ERC-4337 路径对照
形态顶层入口执行逻辑状态所在地址
经典 EOA协议验证交易签名默认无自定义账户代码EOA 地址
传统合约账户被交易或内部消息调用本地址部署的运行时代码合约地址
EIP-7702 委托 EOA签名交易;也可被调用委托指示器指向的实现代码原 EOA 地址
传统 ERC-4337 合约路径UserOperation 经 EntryPoint 执行智能账户合约的验证与执行逻辑通常为智能账户合约地址;与 7702 组合时为原 EOA 地址
安全边界

EIP-7702 授权指向的代码对账户具有极强能力。规范明确提醒:应用不应诱导用户直接签署任意授权, 钱包应审计、筛选并通过标准化接口管理委托。把一次授权当成普通“登录签名”,可能交出整个账户执行权。[4]

07 · ERC-4337

智能账户:把授权规则本身变成程序

ERC-4337 不修改共识协议,而是在上层建立一条 UserOperation 路径。

经典 EOA 的原生授权规则很硬:给出满足协议的签名,或不给。 智能账户希望把“什么算授权”交给代码:两把钥匙共同批准、大额转账等待 24 小时、 丢失主设备后由守护人恢复、某个应用只获得每日小额额度,甚至由赞助者支付 Gas。

“智能账户”首先描述的是一组可编程授权与执行能力,不是协议状态中新增加的 第三套账户数据结构。今天它可以表现为 ERC-4337 智能账户合约,也可以由 EIP-7702 委托 EOA 接入相似的账户逻辑。

01 · USEROP

构造 UserOperation

它像交易请求,但不是协议原生交易;签名语义由智能账户实现定义。

02 · BUNDLER

Bundler 收集打包

Bundler 模拟多个 UserOperation,再把它们装进一笔普通以太坊交易。

03 · ENTRYPOINT

EntryPoint 协调验证

单例合约调用各智能账户验证逻辑,并处理执行、费用与可选 Paymaster。

04 · ACCOUNT

智能账户执行调用

验证通过后,账户合约按自身规则批量调用应用或转移资产。

最重要的边界

ERC-4337 没让“合约账户直接进入基础交易池”。Bundler 最终提交的仍是一笔协议认识的交易, 调用 EntryPoint;UserOperation 是上层对象,验证逻辑发生在合约系统中。[5]

两个 nonce,不要混用

UserOperation 的 nonce 属于 EntryPoint 与智能账户这条上层验证路径,不是账户四字段中的协议 nonce。 常见 EntryPoint 把它组织成 192 位 key 加 64 位顺序号,以支持多条独立序列; Bundler 提交外层协议交易时,还会另外消费 Bundler 发送账户自己的协议 nonce。[5]

EIP-7702 与 ERC-4337,不是二选一

EIP-7702 从协议层扩展 EOA,让既有地址可以委托智能账户逻辑; ERC-4337 提供成熟的 UserOperation、Bundler、EntryPoint 与 Paymaster 流程。 一个委托 EOA 可以使用兼容 ERC-4337 的实现,从而保留原地址和资产,同时接入智能账户基础设施。 当一个 Bundle 携带 7702 授权时,Bundler 的外层提交必须使用 0x04 Set Code 交易类型,而不是把 UserOperation 直接变成协议交易。

但“可编程”不自动等于“更安全”。恢复人可能串谋,模块可能有漏洞,Paymaster 可能审查, 升级权限可能被滥用。账户抽象只是把固定风险变成可设计的规则; 好设计需要最小权限、可审计代码、明确升级路径和用户可理解的签名界面。

四种控制路径的对照视图

经典 EOA

协议固定验证 secp256k1 签名;简单、兼容广,但恢复、限额、批处理能力有限。

KEY → TX
传统合约账户

代码定义行为,但传统入口仍依赖某个 EOA 交易或另一个合约调用。

CALL → CODE
委托 EOA

EOA 签署委托,保留原地址;调用时使用委托实现代码和本地址状态。

KEY + DELEGATE
4337 合约路径

账户合约自定义 UserOperation 验证;与 7702 组合时,同一管线也可服务状态留在原地址的委托 EOA。

RULES → USEROP

08 · Precision & safety

七个最容易带进实战的误区

账户模型学错,通常不是考试失分,而是签错授权。

“地址就是账户,复制地址等于复制账户。”

地址只是公开索引。复制地址只能让别人知道去哪里查询或转账; 控制账户需要满足签名或代码授权规则。不要把公开地址与秘密私钥混为一谈。

“我的代币都存放在 EOA 的 balance 字段里。”

账户的 balance 字段是原生 ETH。ERC-20 余额通常位于代币合约的存储映射, NFT 所有权也位于对应合约状态。钱包把这些异构状态聚合成资产列表。

“合约账户没有私钥,所以合约资产没人能动。”

合约资产由代码控制。代码可能允许管理员 EOA、多签、DAO、时间锁或任何调用者在特定条件下转移。 要阅读权限规则,而不是只看地址类型。

“任何失败交易都像从未发生,什么也不扣。”

执行回滚会撤销调用造成的状态写入与价值转移,但已完成的计算仍需支付 Gas, 顶层交易 nonce 也会前进。签名前应区分模拟失败、上链回滚和进入区块前被拒绝。

“只要某地址有 code,它就一定是传统合约账户。”

Pectra 后,EOA 可能持有 EIP-7702 委托指示器。区块浏览器、钱包和应用不能只用 “代码是否为空”推断所有账户行为。

“EIP-7702 授权只是给某个 DApp 一个小权限。”

原始委托授权让指定实现代码在账户上下文执行,能力非常强。 细粒度权限应由经过审计的委托实现和标准模块提供;不要向陌生应用签署任意授权元组。

“ERC-4337 是以太坊把全部 EOA 换成合约账户的硬分叉。”

ERC-4337 明确采用不改共识协议的上层路径:UserOperation、独立传播、Bundler 和 EntryPoint 合约。 它与 EOA 和普通交易体系并行,并可与 EIP-7702 组合。

看到签名请求时,先问五个问题

  1. 01

    我在授权哪一种对象?普通交易、消息签名、代币 allowance、Permit、UserOperation 还是 EIP-7702 授权?

  2. 02

    谁会验证它?协议、某个代币合约、EntryPoint、钱包模块还是应用后端?

  3. 03

    权限边界是什么?一次调用、固定额度、特定目标、某条链,还是无期限的广泛控制?

  4. 04

    能否撤销或替换?撤销动作是否也需要原密钥、管理员、时间锁或新的链上交易?

  5. 05

    失败时谁承担什么?Gas、资产、nonce、赞助额度与重放风险分别落在哪个账户?

用户安全结论

“连接钱包”不必然转移资产,“签名”也不必然安全。真正要读的是签名对象和验证规则。 不理解的 EIP-7702 委托、无限代币授权或智能账户模块,不要因为界面写着“登录”就确认。

09 · Recap

把整课压缩成一条控制链

从公开地址开始,沿着授权、执行与状态更新走到新的 stateRoot。

地址索引记录 读取 nonce / 余额 / 代码 验证签名或账户规则 执行转账或代码 原子更新多处状态 得到新 stateRoot
  1. 01

    地址是索引,不是钱包。钱包是帮助你管理授权和交互的工具。

  2. 02

    账户是状态记录。核心字段是 nonce、原生 ETH 余额、storageRoot 与 codeHash。

  3. 03

    账户模型维护当前状态。UTXO 模型则维护尚未花费的输出集合。

  4. 04

    经典 EOA 由签名授权顶层交易。传统合约账户由代码响应调用。

  5. 05

    一次调用可原子改变多个账户。应用内部会计与协议原生余额是两层状态。

  6. 06

    EIP-7702 让 EOA 可委托代码。代码来自实现地址,执行上下文与状态留在原 EOA。

  7. 07

    ERC-4337 在上层抽象账户。UserOperation 经 Bundler 与 EntryPoint 调用智能账户。

  8. 08

    可编程不自动等于安全。权限、升级、恢复、赞助与模块都要进入威胁模型。

现在检查你的理解

1. “地址”和“钱包”的关系,哪项最准确?

2. 一个 EOA 的 USDC 余额通常存在哪里?

3. 经典 EOA 的交易 nonce 主要解决什么?

4. EIP-7702 委托最准确的描述是什么?

5. ERC-4337 如何进入以太坊区块?

6. 一笔已上链交易执行回滚后,哪项通常仍然发生?

10 · Sources

术语与一手资料

“EOA 无代码”已标为经典模型;现代边界以当前 EIP 与官方文档校准。

核心术语

地址 ADDRESS

20 字节公开值,用作执行层状态与消息目标的索引。地址本身不是秘密,也不等于钱包应用。

外部账户 EOA

经典模型中由私钥签名授权、可发起顶层交易的账户。EIP-7702 允许它设置代码委托指示器。

合约账户 CONTRACT ACCOUNT

由部署的 EVM 代码控制行为、拥有独立地址与持久状态的账户;传统模型中被调用后才执行。

nonce ACCOUNT NONCE

账户计数器。对经典 EOA 主要提供交易顺序与重放保护;对合约还关联创建计数。

存储根 STORAGE ROOT

对某账户持久键值存储的密码学承诺。具体 trie 结构会在第十一章展开。

委托指示器 DELEGATION INDICATOR

EIP-7702 写入 EOA 代码字段的特殊 23 字节值 0xef0100 || address,指向要执行的实现代码。

UserOperation ERC-4337

描述智能账户请求的上层对象,不是协议原生交易;由 Bundler 打包并经 EntryPoint 执行。

钱包 WALLET

帮助用户管理密钥或账户权限、构造签名、连接网络和展示资产的界面或软件。

官方一手资料

  1. 01
    ethereum.org — Ethereum accounts 两类经典账户、四个账户字段、地址与钱包的官方基础说明。 页面更新:2026-04-13 · 核对:2026-07-25
  2. 02
    Ethereum Execution Layer Specification 当前执行层状态转换与分叉规则的可执行规范仓库。 持续更新的协议规范
  3. 03
    EIP-7702 — Set Code for EOAs Set Code 交易、授权元组、委托指示器、执行上下文与安全考虑的规范来源。 Pectra 协议变更 · 核对:2026-07-25
  4. 04
    ethereum.org — Pectra EIP-7702 guidelines 钱包、应用与硬件签名设备集成委托时的安全与互操作建议。 页面更新:2026-06-06
  5. 05
    ERC-4337 — Account Abstraction Using Alt Mempool UserOperation、Bundler、EntryPoint、Paymaster 与“无需共识协议变更”的正式规范。 持续更新的 ERC 规范
  6. 06
    ethereum.org — Account abstraction EIP-7702 与 ERC-4337 两条账户抽象路径、恢复与 Gas 赞助的官方概览。 页面更新:2026-06-24
  7. 07
    ethereum.org — Gas and fees 执行失败、状态回滚与已消耗 Gas 仍被计费的官方说明。 核对:2026-07-25
  8. 08
    ethereum.org — Transactions 签名交易字段、nonce、value、Gas 与交易生命周期。 页面更新:2026-03-12
  9. 09
    EIP-161 — State trie clearing 不存在、空账户、非空账户与状态清理边界的协议历史来源。 Spurious Dragon 协议规则
下一步

账户模型已经立住。进入第五章后,我们会把“有效签名”拆成私钥、公钥、地址、 椭圆曲线与 Keccak-256,再回头验证:为什么网络能相信授权,而永远不需要看见你的私钥。