Ethereum learning path · 04.03

没有私钥,谁在控制合约账户?

从一条地址背后的四个状态字段出发,把“代码控制”拆成 创建、调用、授权、资产与升级五条可以逐步验证的因果链。

  • 04 · 03 账户模型
  • 58 MIN 阅读与实验
  • 0 → 深入 无需编程基础

The thesis

“由代码控制”不是一句拟人化描述。它意味着:这个地址上的资产和状态, 若要主动支出 ETH、写自身 storage 或继续调用,必须在一次有效执行中, 沿着部署代码允许的路径发生。

01 · Orientation

先拆掉三个误会

先建立一个不会在后面反复坍塌的最小模型。

目录原题 · 合约账户:没有私钥,由部署的代码控制

以太坊把世界状态组织成“地址 → 账户状态”的映射。 经典入门模型把账户分为两类:外部账户 EOA 由私钥签名控制; 合约账户由 EVM 字节码的执行规则控制。两者都可以有地址、持有 ETH, 也都可以成为消息调用的目标。1

误会一

“没有私钥”就是没有任何人可以影响它。

更准确

合约地址没有一把原生私钥,但代码可以把某个 EOA 设为管理员,也可以要求多签、时间锁、DAO 投票,甚至故意不留任何管理员。

误会二

合约像后台程序,会按时间表自己醒来做事。

更准确

普通合约是被动程序。它必须在某笔顶层交易所引发的执行中被调用;所谓自动化服务,最终也要有人或服务把交易送进链。

误会三

“由代码控制”就等于去中心化、不可升级、没有风险。

更准确

代码可能写着“owner 一人可升级”,也可能存在漏洞。代码控制只说明状态转换的入口,不替代码的治理质量与安全性背书。

一句精确定义

传统合约账户,是一个拥有地址、余额、持久存储和运行时代码的链上状态对象。 它不能签发顶层交易;当消息调用抵达时,EVM 执行它的代码, 代码可以在协议允许的范围内读写状态、转移价值或继续调用其他账户。

学完本课,你应该能做到

01

读懂账户

解释 nonce、balance、storageRoot 与 codeHash 各自承诺什么。

02

分清动作

区分顶层交易、消息调用与区块浏览器里的“内部交易”。

03

追踪身份

沿调用链判断 msg.sender、tx.origin 与真正被读写的 storage。

04

识别边界

看懂代理升级、合约钱包、SELFDESTRUCT 与 EIP-7702 的现代语义。

02 · Account anatomy

一条地址背后,只有四个协议字段

“合约”不是一团代码;它首先是世界状态中的一条账户记录。

地址是 20 字节的索引。执行客户端用它找到一条账户状态; 账户状态再通过哈希指向代码与存储。把界面、Solidity 源码和项目名字暂时拿走, 协议真正维护的是下面这四个值。1

Interactive · state x-ray

切换三种账户剖面

传统合约账户:有运行时代码与可持久化 storage,没有与地址原生绑定的交易签名私钥。
图 01 经典二分仍是最好的入门坐标;右侧的 EIP-7702 模式会在本课第 10 节完整解释。

codeHash 不是 Solidity 源码

EVM 执行的是编译后的字节码。链上账户保存 codeHash, 客户端按哈希找到运行时代码;开发者公开的 Solidity 源码通常由区块浏览器做 “源码验证”,证明它能编译出同一份字节码。验证源码很重要, 但它不是账户四字段之一。4

storage、memory 与 transient storage 不是一回事

三类 EVM 数据区域的生命周期、归属与用途
区域 活多久 属于谁 典型用途
Storage 跨交易持久存在 某个账户地址 owner、余额映射、订单状态、代理实现地址
Memory 当前调用帧结束即消失 当前 EVM 调用帧 临时字节数组、ABI 编解码、返回数据
Transient storage 同一交易内共享,交易结束清空 执行中的账户 跨内部调用的短期锁与临时状态

经典 EOA 与传统合约账户,逐项对照

经典外部账户与传统合约账户逐项对照
维度 经典 EOA 传统合约账户
原生控制入口 与地址对应的私钥签名 消息调用抵达后执行 runtime code
地址来源 公钥 Keccak-256 哈希的末 20 字节 CREATE / CREATE2 规则推导
能否发起顶层交易 不能;只能在执行中继续消息调用
收到消息调用 经典模型下没有代码可执行 加载运行时代码并建立 EVM 调用帧
Nonce 的主用途 交易顺序与防重放 创建新合约时的地址序号
创建成本 链下生成密钥本身不产生链上费用 执行 initcode 与保存 runtime code 消耗 Gas
能否持有 ETH

这里先使用经典模型建立坐标;EIP-7702 委托 EOA 的例外见第 10 节。

“private” 不等于秘密

Solidity 的 private 只是禁止别的合约用语言级接口直接访问。 storage 仍进入公共链状态,观察者可以读取原始存储槽。

03 · Control

控制,不是拥有一把看不见的钥匙

EOA 与合约账户的根本差异,是状态改变前经过哪一道授权门。

EOA 的原生授权门由协议固定:验证签名并恢复 sender。 合约账户的授权门由代码定义:EVM 执行函数,只有所有条件都通过, 那条状态转换路径才会继续。

两类账户的“控制门”

EOA · protocol gate

签名是否来自这条地址?

协议按固定密码学规则验证交易签名、nonce、余额与费用条件。

  1. 01对交易载荷求哈希
  2. 02从签名恢复公钥与地址
  3. 03检查 sender、nonce 与支付能力
  4. 04有效交易进入状态转换

Contract · programmable gate

代码允许这次动作吗?

协议不认识“owner”。owner、多签和治理权限都是字节码与 storage 定义的应用规则。

  1. 01消息调用抵达合约
  2. 02按 calldata 选择代码分支
  3. 03检查调用者、签名、时间或投票
  4. 04通过则写状态或继续 CALL;失败则 REVERT
图 02 “代码控制”真正带来的能力,是把固定的一把钥匙扩展为可编程的授权策略。

Interactive · 2-of-3 vault

让一个合约钱包决定是否放行

假设金库代码写死了规则:Alice、Bob、Carol 三位 owner 中至少两人对同一动作签名, 并且 24 小时时间锁已经结束,合约才允许向外转账。

有效签名:0 / 2 REVERT · 未达到门槛
当前没有足够签名。合约不会“听某个人的话”,只会执行它被部署时写入的验证逻辑。

因此,“谁控制合约”有三层答案

01 · Protocol

直接控制者

运行时代码决定哪些调用路径可以改变该地址的 ETH 与 storage。

02 · Governance

规则修改者

若代码支持升级或管理员函数,owner、多签或 DAO 可能改变未来行为。

03 · Operations

触发者

任何人都可能发起调用;但“能按按钮”与“调用会被允许”是两回事。

04 · Reality

不可救援边界

若没有提款路径或所有授权凭证丢失,不存在一把“合约私钥”绕过代码救出资产。

04 · Creation

合约账户不是注册出来的,是执行出来的

部署本身就是一次状态转换:先运行初始化代码,再把返回值保存为运行时代码。

创建合约时,输入不是“请保存这段源码”。交易或另一个合约提供 initcode;EVM 执行它。initcode 可以运行 constructor、 写初始 storage,最后返回一段字节。只有这段返回字节成为新账户的 runtime code2

从源代码到链上账户的五步

01

编写与编译

Solidity / Vyper 源码编译成 initcode 与将被返回的 runtime code。

02

提交创建

EOA 发部署交易,或执行中的合约调用 CREATE / CREATE2。

03

推导地址

协议根据创建者、nonce,或 salt 与 initcode 哈希计算 20 字节地址。

04

运行 initcode

constructor 执行并写初始 storage;失败时该创建子执行回滚。

05

保存 runtime

initcode 返回的字节成为账户代码;部署者为计算与代码存储支付 Gas。

图 03 constructor 只在创建时运行,不是今后每次调用都会重跑的函数。

地址如何在账户出现前就被算出来?

CREATE last20( keccak256( RLP([creator, creatorNonceBeforeIncrement]) ) )
CREATE2 last20( keccak256( 0xff ++ deployer ++ salt ++ keccak256(initcode) ) )

CREATE 的地址取决于实际创建者及其创建 nonce。若 Alice 调用 Factory, 再由 Factory 创建新合约,公式里的 creator 是 Factory,不是 Alice。 CREATE2 额外承诺 salt 与 initcode 哈希, 因而可以在部署前计算“反事实地址”。6

公式使用创建动作发生前的 creator nonce;主网新创建的合约账户 nonce 通常按 EIP-161 从 1 起步。内部 CREATE / CREATE2 失败时,调用者会得到失败结果并可选择继续; 它不必然让整笔顶层交易一起 REVERT。15

可预测,不等于可占领

CREATE2 不会覆盖旧代码。若目标地址已有非零 nonce 或非空代码,创建必须失败; 但目标地址只是提前收到了一些 ETH,并不会单独造成地址冲突。 7

CREATE2 也不会生成私钥

合约地址是从部署条件推导的结果,不对应部署者持有的一把密钥。 “我知道这个地址怎样算出来”与“我能为这个地址签交易”毫无等价关系。

05 · Message calls

合约不会自己醒来

一切用户级执行都嵌在某笔顶层交易之中,但一笔交易可以展开成整棵调用树。

普通合约账户不能签名、广播,也不能成为一笔传统顶层交易的 sender。 但当它已经因为消息调用而运行时,可以用 CALLSTATICCALLDELEGATECALLCREATE 同步触发更多执行。3 14

Interactive · one transaction

逐步走过一棵调用树

EOA 0xAlice 签名顶层交易
Contract A 0xVault 2-of-3 验证
Contract B 0xToken 更新余额映射
图 04 整棵树只有一个顶层交易哈希与一个交易 nonce;内部 CALL 是执行轨迹,不是新交易。

“内部交易”是区块浏览器语言,不是协议里的第二种交易

浏览器常把合约发出的 CALL 显示为 internal transaction,方便人阅读。 但它没有独立签名、独立交易 nonce 或独立交易哈希。更严谨的叫法是 内部消息调用call trace。 如果金库后续调用失败且异常没有被处理,storage 写入、价值转移、日志和创建结果 可随执行一起回滚;但顶层 sender nonce 不回滚,已经消耗的 Gas 仍然收费。 对 EIP-7702 的 type-4 交易,执行开始前已处理的有效代码委托也不会因后续执行失败而回滚。 10

读取也可能“运行代码”

钱包用 eth_call 查询 view 函数时,节点会本地模拟执行; 它不进入区块、不产生持久状态,也不是一笔已经上链的交易。 同一个 view 函数若被链上合约内部调用,仍会消耗这笔交易的 Gas。

06 · Execution context

执行谁的代码,改谁的状态?

调用不是只跳到另一个函数;每一层都会建立一份精确的执行上下文。

EVM 每进入一层调用,都要确定:当前地址是谁、加载哪段代码、读写哪份 storage、 直接调用者是谁、带来多少 ETH、能否写状态,以及还剩多少 Gas。 CALLDELEGATECALLSTATICCALL 正是在这些维度上做出不同选择。5

Interactive · execution frame

同样调用实现合约,三种语义

CALL · enter callee context

Proxy 0xProxy
  │
  └─ CALL 0xLogic
       code    = Logic.code
       storage = Logic.storage
       address(this) = 0xLogic
EXECUTED CODE 0xLogic.code 具体执行哪一份 EVM 字节码
STORAGE / BALANCE 0xLogic 状态写入与余额属于哪个地址
address(this) 0xLogic 代码在执行中观察到的当前地址
msg.sender 0xProxy 当前调用帧的直接调用者
msg.value 本次 CALL 指定的 value 这一层携带的原生 ETH 数量
STATE WRITES 允许 尝试写状态时是否被本调用类型禁止
CALL 进入被调用者的代码与状态上下文;在 Logic 内,直接调用者是 Proxy。
图 05 代理升级之所以可行,关键正是 DELEGATECALL 能“借代码、留状态”。

普通 CALL 链里,msg.sender 随直接调用者逐层变化

Alice EOA— tx →合约 A— CALL →合约 B— CALL →合约 C
普通 CALL 链中各执行位置的 msg.sender、tx.origin 与授权依据
执行位置 msg.sender tx.origin 应该用谁做普通授权
合约 A Alice Alice msg.sender
合约 B 合约 A Alice msg.sender
合约 C 合约 B Alice msg.sender

msg.sender 是当前层的直接调用者;tx.origin 是最外层交易 sender。后者穿过整条调用链不变,因此恶意合约可以诱导用户先调用自己, 再转调一个错误使用 tx.origin 做授权的受害合约。 不要用 tx.origin 判断“是不是本人”或“有没有合约参与”。 这里说的逐层变化针对 CALL / STATICCALL;DELEGATECALL 会保留外层 msg.sendermsg.value

DELEGATECALL 的锋利边缘

实现代码会读写调用者的 storage。若实现使用的槽位布局与代理不兼容, 或升级权限被夺走,固定地址上的全部状态都可能被破坏。可升级不是代码不变性的反例; 它是固定代理代码主动留下的一条“借用别处代码”的路径。

07 · Asset truth

合约究竟把资产“放”在哪里?

ETH、ERC-20 与 NFT 都可以归属于同一地址,但三者写在不同账本。

“金库合约持有 100 ETH、10,000 USDC 和一枚 NFT”是方便人类理解的说法。 协议实际看到的是三处不同状态:ETH 在金库账户自己的 balance; USDC 与 NFT 的归属则记录在各自代币合约的 storage 中。

一个地址,三本账

01 · Native ledger

ETH

直接进入 0xVault 账户状态的 balance 字段,以 wei 计数。

state[0xVault].balance
= 100 ETH
02 · Token contract

ERC-20

余额是 USDC 合约 storage 中以持有人地址为键的一条记录。

USDC.balances[0xVault]
= 10,000 USDC
03 · NFT contract

ERC-721

所有者是 NFT 合约 storage 中 tokenId 对地址的映射。

Collection.ownerOf[42]
= 0xVault
图 06 账户的 balance 字段只统计原生 ETH;“钱包总资产”是索引多份合约状态后得到的视图。

代码可以拒收 ETH 吗?答案不是简单的是或否

普通带 value 的 CALL 抵达合约时,会执行 receive()fallback();代码可以接受,也可以 REVERT。但“账户余额增加” 并不总要经过收款方代码。例如另一个合约执行 SELFDESTRUCT 时可把 ETH 余额转给目标地址,而不会调用目标的收款函数。

接收路径

常规 CALL + value:进入收款合约执行;是否成功由 payable 入口与代码决定。

余额路径

某些协议语义可直接增加目标 balance。因此“代码没有收款函数”不能证明余额永远为零。

能拥有,不代表一定能取出

资产从某个账本上归属于合约地址,只说明当前状态;它不会自动生成提款能力。 若 runtime code 没有一条能让条件满足后转出 ETH 或调用 token 合约的路径, 资产就可能永久锁在这个地址。这正是“没有私钥救援通道”的实际含义。

08 · Smart accounts

合约钱包:把“谁能签”变成一段程序

它不是给合约偷偷配一把私钥,而是让合约验证用户提交的证明。

多签钱包、社交恢复钱包与限额钱包通常都是合约账户。 人仍可持有私钥、Passkey 或其他凭证,但这些凭证控制的是 代码是否认可一次操作,不是从合约地址反推出一把私钥。

ERC-4337 中,一次智能账户操作怎样上链

01 用户签意图 生成 UserOperation,不是执行层原生交易。
02 Bundler 收集 模拟验证并把多个操作打包。
03 提交交易 Bundler 才是顶层交易 sender。
04 EntryPoint 验证 调用智能账户自定义验证逻辑。
05 账户执行 验证通过后调用目标应用,可由 Paymaster 赞助费用。
图 07 ERC-4337 没有让普通合约直接成为协议层交易 sender;它用应用层对象、Bundler 与 EntryPoint 组织执行。

合约也可以“签名”,但含义不同

ERC-1271 定义了 isValidSignature(hash, signature): 应用可询问某个合约“你是否认可这份签名代表你”。合约可以要求一把 owner key、 2-of-3 多签、BLS 聚合签名,甚至根据时间和当前状态改变答案。 它返回的是代码判定结果,不是从合约地址恢复出公钥。8

EOA SIGNATURE

协议验证

签名方案和 sender 恢复规则由交易类型与协议规定;私钥是最终控制根。

CONTRACT SIGNATURE

合约回答

调用验证函数,代码决定任意字节是否代表当前账户;规则可以是状态相关的。

为什么这叫账户抽象

它把“有效账户操作必须是一把 secp256k1 私钥签出的固定格式交易” 抽象为“账户能用自己的程序证明这次动作有效”。于是批量操作、费用代付、 会话密钥、Passkey、每日限额与社交恢复都能进入同一账户体验。 9

09 · Lifecycle

代码不变,为什么行为还能升级?

理解“不可变”,必须把地址上的代码与系统最终执行的业务逻辑分开。

一个普通、已部署合约地址上的 runtime code 通常不能被就地改写。 但这份固定代码完全可以写着:“把每次调用转交给 storage 里记录的实现地址。” 于是代理地址与资产状态不变,业务逻辑却能通过替换实现地址而升级。

固定代理,借用可替换实现的代码

Stable address

Proxy · 0xVault

用户始终调用这里;ETH、owner、余额与实现地址都留在代理的账户状态。

slot.owner → 0xMultiSig slot.implementation → 0xLogicV2 slot.userBalances → …
delegatecall
借代码
留状态

Replaceable logic

Implementation · V2

提供函数实现,但执行时读写的仍是 Proxy storage;升级通常是改实现地址。

codeHash → V2 bytecode own storage → usually unused address(this) → 0xVault
图 08 代理字节码本身没有变化;“可升级”能力正是它从第一天起就写进代码的控制规则。

SELFDESTRUCT 今天通常不会删除合约

自 Cancun 升级采用 EIP-6780 后,一个早已存在的合约执行 SELFDESTRUCT(beneficiary),会停止当前执行帧并把全部 ETH 转给 beneficiary,但不会删除账户、代码或 storage。 只有合约在同一笔交易中刚创建又 selfdestruct,才保留旧式删除行为。 两个边界要单独记:既存合约若把自己指定为 beneficiary,余额净变化为零; 同交易新建合约若这样做,余额会被销毁。 12

EIP-6780 下 SELFDESTRUCT 在两类创建时序中的语义
场景 余额 代码 Storage 账户
合约早已存在 全部转给 beneficiary;若指向自己则净变化为零 保留 保留 保留
同一交易内刚创建 转移;若指向自己则销毁 交易结束删除 交易结束删除 删除
现代安全结论

不要把 SELFDESTRUCT 当作可靠的升级、清理或紧急停止方案。 “先销毁、下笔交易再用 CREATE2 原址部署另一套代码”的旧式 metamorphic 模式,对既存合约已不成立;该操作码也处于弃用方向。

10 · 2026 boundary

EIP-7702 以后,旧二分需要加一条脚注

传统合约账户依然没有私钥;变化的是“EOA 必定没有代码”不再是完整事实。

Pectra 已于 2025 年 5 月 7 日在以太坊主网激活 EIP-7702。 EOA 可以签署授权,在自己的 code 字段写入一个 23 字节的 代码委托标记,让调用执行另一地址的代码,同时保留 EOA 自己的地址、余额与 storage 上下文。10 11

经典模型与现代执行边界

Classic mental model

EOA = key, no code

codeHash = keccak256("")
  • 私钥签发顶层交易
  • 收到普通调用时没有代码可执行
  • 适合作为第一层学习坐标

EIP-7702 delegated EOA

Key + delegation indicator

0xef0100 || delegate_address
  • Authority 私钥签署授权;外层 type-4 交易可由本人或赞助者提交
  • 执行时到 delegate_address 取代码
  • 代码在 EOA 自己的地址与 storage 上下文运行
  • 委托持久存在,直到被替换或清除
图 09 EIP-7702 没有把传统合约账户变成交易 sender;它让 EOA 获得可编程执行行为。
代码不会因为它是 sender 就自动运行

只有一笔交易或消息调用的 destination 指向委托 EOA 时, EVM 才解析委托并执行代码。典型自付费流程可以是该 EOA 向自己发送交易, 再由委托代码调用真正目标;赞助流程也可由 relayer 把授权放进外层 type-4 交易。

哪些旧口诀失效了?

EIP-7702 激活前后的账户判断口诀与安全含义
旧口诀 2026 年更准确的说法 安全含义
EOA 一定没有代码 经典 EOA 无代码;委托 EOA 可带代码指示器并执行委托逻辑。 不能再把 code length 当作可靠的人类/合约分类。
有代码的账户不能发交易 任意普通代码仍不能;有效 7702 委托标记是协议明确允许的例外。 检查“有无代码”不能替代对调用行为的分析。
tx.origin == msg.sender 说明没有中间合约 7702 委托 EOA 可在顶层帧内执行代码并继续调用。 不要把这个相等关系当防重入或身份保证。
撤销委托就完全恢复空白 EOA 代码标记可以清除,但此前委托逻辑写入的 storage 不会自动清空。 更换委托必须考虑存储布局与残留状态。
最终心智模型

“EOA 与合约账户”仍是理解账户来源与顶层交易权限的基础分类; 但“有没有代码”和“能不能表现出可编程行为”已经不是可靠的二元身份测试。 面向 2026 年开发,更安全的默认假设是:任何地址都可能表现出程序化行为。

委托不等于放弃私钥

EOA 的原私钥仍能替换或清除委托。把 EOA 委托给多签逻辑, 并不会自动消除这把私钥作为最终授权根的地位;委托代码自身的签名、 防重放、初始化与 storage 迁移也都是安全关键。

11 · Recap

把整条因果链压缩成一句话

如果你能从输入一路讲到新状态,就真正理解了“代码控制”。

EOA / Bundler 提交顶层交易 消息调用抵达地址 按 codeHash 取得代码 EVM 建立调用上下文 代码检查授权与条件 写 storage / 转 ETH / 继续 CALL 执行状态提交或回滚(nonce / Gas 有例外)

合约账户没有一把可以跳过这条链的原生私钥。它之所以能“转钱”“创建合约” 或“调用 DeFi”,不是因为它在链外签发了新交易,而是因为当前交易的执行 已经进入它的代码路径,并由 EVM 把这些动作纳入同一次原子状态转换。

十个常见误区,逐个翻面

合约没有私钥,所以没有人能控制它。

错误。代码可以指定 owner、多签、时间锁或治理。没有的是协议原生的合约地址私钥,不是所有社会与治理控制。

合约向外转账,就是合约发起了一笔新交易。

错误。通常是当前交易执行树中的内部 CALL,没有独立签名、交易 nonce 或交易哈希。

合约持有 USDC,所以 USDC 在它的 balance 字段里。

错误。balance 只记原生 ETH;USDC 归属记录在 USDC 合约的 storage。

CREATE2 算得出地址,所以部署者拥有该地址的私钥。

错误。地址由部署条件确定;可预测不产生私钥,也不能覆盖已有非空代码或非零 nonce 的账户。

代理合约可升级,说明链上代码可以被随意改写。

错误。代理自己的代码通常不变;它固定地通过 DELEGATECALL 借用 storage 指向的另一份实现代码。

现代 SELFDESTRUCT 总会删除代码和 storage。

错误。对早已存在的合约,它通常只转移全部 ETH 并停止当前帧,代码、storage 与账户仍保留。

有代码的地址一定是传统合约账户。

错误。EIP-7702 委托 EOA 可带 23 字节代码指示器;预编译等协议边界也让 code length 分类不可靠。

没有代码的地址一定是普通 EOA。

错误。构造函数执行期间新地址尚无 runtime code,预编译有协议行为而不靠普通账户代码,空代码账户也可能存在。

tx.origin 是最初用户,所以最适合做授权。

错误。恶意中间合约与 7702 执行都能破坏这种假设;普通授权应基于当前调用的 msg.sender 与明确签名验证。

代码控制就天然代表去中心化与安全。

错误。代码可能有单一管理员、升级入口或漏洞。应分别审查执行规则、升级治理与实际密钥分布。

六题理解测验

01 · 传统合约账户为什么不能成为顶层交易 sender?

02 · 部署完成后,账户保存的是哪段代码?

03 · Alice → A → B 的 CALL 链中,在 B 内谁是 msg.sender?

04 · DELEGATECALL 最关键的语义是哪一项?

05 · “0xVault 持有 10,000 USDC”在状态里通常怎样表示?

06 · 关于 EIP-7702,哪一句最准确?

12 · Sources

术语表与一手资料

关键事实以 Ethereum 官方文档、执行规范与已定稿 EIP 为依据;页面核对日期为 2026-07-25。

本课最小术语表

本课关键术语与精确定义
术语 本课中的精确定义
Account 世界状态中由地址索引的一条 nonce、balance、storageRoot、codeHash 记录。
Contract account 拥有运行时代码、在消息调用到达时按代码执行的账户;传统合约账户没有原生交易签名私钥。
Transaction 进入区块的顶层、带签名指令;可产生一棵内部消息调用树。
Message call EVM 执行中的同步调用,建立新调用帧;不是独立顶层交易。
Runtime code 部署 initcode 执行后返回并保存在账户上的 EVM 字节码。
Smart contract wallet 用合约代码验证授权并执行用户意图的账户系统,可实现多签、恢复、限额与费用代付。
Delegated EOA 通过 EIP-7702 持有代码委托标记、可在自身上下文执行委托逻辑的 EOA。
  1. 01
    Ethereum.org · Ethereum accounts 账户类型、四个账户字段、EOA 密钥与“账户不等于钱包”的官方入门说明。 页面更新:2026-04-13
  2. 02
    Ethereum.org · Ethereum Virtual Machine 状态转换、合约创建、消息调用、持久 storage、memory 与 transient storage。 页面更新:2026-04-03
  3. 03
    Ethereum.org · Transactions 顶层交易、合约创建交易、合约调用与 eth_call 的官方说明。 页面更新:2026-03-12
  4. 04
    Ethereum.org · Verifying smart contracts 源码、编译结果与链上字节码验证之间的关系。 Ethereum 官方开发文档
  5. 05
    Ethereum.org · Opcodes for the EVM CALL、DELEGATECALL、STATICCALL、CREATE、CREATE2 与 SELFDESTRUCT 的当前操作码语义索引。 页面更新:2025-09-11
  6. 06
    EIP-1014 · Skinny CREATE2 CREATE2 地址公式、initcode 哈希与地址冲突条件。 Final · Core
  7. 07
    EIP-684 · Revert creation in case of collision 目标已有非零 nonce 或非空代码时,合约创建必须失败。 Final · Core
  8. 08
    ERC-1271 · Standard Signature Validation Method for Contracts 合约通过 isValidSignature 自定义“什么签名代表我”。 Final · ERC
  9. 09
    ERC-4337 · Account Abstraction Using Alt Mempool UserOperation、Bundler、EntryPoint、智能账户验证与 Paymaster 的规范。 Final · ERC
  10. 10
    EIP-7702 · Set Code for EOAs set-code 交易、委托指示器、执行解析、EOA 发起交易例外与安全边界。 Final · Core · Pectra
  11. 11
    Ethereum Foundation · Pectra Mainnet Announcement Pectra 主网激活时间与 EIP-7702 账户能力概览。 Ethereum Foundation · 2025-04-23
  12. 12
    EIP-6780 · SELFDESTRUCT only in same transaction 现代 SELFDESTRUCT 对余额、代码、storage 与账户删除的分场景规则。 Final · Core · Cancun
  13. 13
    Ethereum Execution Specifications · Prague fork types 当前执行层账户数据类型、序列化字段与代码委托时代的规范表示。 可执行协议规范
  14. 14
    EIP-3607 · Reject transactions from senders with deployed code 普通非空代码账户不得成为交易 sender;EIP-7702 后,有效委托指示器是协议规定的例外。 Final · Core
  15. 15
    EIP-161 · State trie clearing 合约创建前 nonce 的递增规则,以及状态回滚时空账户删除也必须回滚的边界。 Final · Core · Spurious Dragon
继续学习

本课先回答“合约账户由什么控制”。下一阶段应把调用成本接上: 第 6 章追踪一笔交易,第 7 章拆 Gas,第 8 章深入 Stack、Memory、 Storage 与 Opcode,第 9 章再进入智能合约完整生命周期。

私钥证明“谁提出请求”;
代码决定“这个地址允许发生什么”。