Page 42 - 《软件学报》2026年第1期
P. 42
郭涛 等: 智能合约可升级技术综述 39
的方法 (如执行 method_call() 操作) 时, 代理合约使用 delegatecall() 函数将调用转发给逻辑合约. 逻辑合约则通过
操作代理合约的状态数据 (通过 getter() 和 setter() 方法) 来完成数据读取和修改. 另一方面, 代理模式引入额外的
代理地址, 使得逻辑和存储合约地址之间的持续调用增加额外 Gas 消耗. 此外, 逻辑合约调用 delegatecall() 操作代
理合约的存储, 如果两者存储布局不匹配, 变量错位会引发关键数据 (如地址或权限) 的覆盖问题. 一旦权限管理
被攻破, 攻击者可以将逻辑合约地址更新为恶意合约地址, 利用 delegatecall() 在代理合约上下文中执行恶意代码,
窃取资金或破坏合约状态. 因此, 根据不同的需求, 衍生出最小代理、透明代理、可升级代理、钻石合约和信标代理等
模型.
① ②
method_call() delegatecall()
代理合约
存储逻辑地址 实现合约 V1
用户 返回值 返回值
③
创建 实现合约 V2
④
图 5 代理模型
1.2 最小代理
2018 年, EIP-1167 提案 [52] 规定了最小代理 (minimal proxy) 的概念, 它允许开发者创建一个代理合约, 该代理
合约可以将调用转发到另一个实现合约 (implementation contract, 也称为基础合约). 图 6 展示最小代理的模型设
计, 支持多个代理合约共享相同的实现代码, 但每个代理拥有独立的存储状态, 从而降低部署成本和存储需求.
①调用
代理工厂 实现合约
请求创建 部署 指向
② 轻量级代理 ③
用户 CloneFactory.sol 合约
调用_clone()方法 Implementation.sol
图 6 最小代理
1) 代理工厂 (proxy factory): 用户将调用工厂的一个函数, 而工厂将克隆一份实施合约的副本, 但拥有自己的
存储空间. 这意味着每个克隆都有相同的逻辑, 但存储状态独立.
2) 代理 (proxy): 代理合约是执行合约的克隆, 但具有独立的存储.
3) 实现合约 (implementation contract): 有时被称为逻辑合约或执行合约, 强调该合约包含实际的业务逻辑, 但
由代理合约调用.
开发者首先需要编写包含业务逻辑的实现合约 Implementation.sol, 然后将其部署到区块链上. 如图 7, 当用户
编写并部署一个代理合约时, 将触发 clone() 函数, 代理工厂将输出代理的地址, 而在代理合约中设置指向实现合
约的地址, 代理合约使用 delegatecall() 函数将调用转发至实现合约.
最小代理模式通过简化代理合约的结构, 显著降低部署和运行时的 Gas 成本. 代理合约本身不包含业务逻辑,
仅存储状态变量, 充当一个静态的前端接口, 它通过极简字节码部署多个合约实例, 利用 delegatecall() 函数将调用
请求转发给后端的实现合约实现业务逻辑. 多个代理合约可以共享同一实现合约, 从而进一步节省部署成本.
尽管最小代理支持实现合约地址的动态更新, 但通常不包含复杂的升级机制和权限验证功能. 升级时无需修
改代理合约, 仅需更新内部引用的实现合约地址. 确保用户和外部系统始终通过统一代理合约接口与智能合约交
互, 从而保证合约地址的一致性与稳定性.
然而, 当多个最小代理共享实现合约时, 整个系统的复杂性显著增加. 实现合约在升级时, 新增状态变量时必
须附加至存储布局的末尾, 避免调整原有变量顺序, 以防存储错位导致关键数据被覆盖或权限被意外篡改, 否则会

