Page 43 - 《软件学报》2026年第1期
P. 43

40                                                         软件学报  2026  年第  37  卷第  1  期


                 引发存储冲突     [53] , 例如管理员地址被覆盖为随机地址, 导致权限被篡改或丢失. 此外, 以太坊中函数调用是根据数
                 据有效负载的前      4  个字节函数选择器     (函数名称及其签名的哈希值) 标识, 4         个字节长度的低碰撞性这意味着两个
                 函数之间可能会发生冲突: 两个具有不同名称的不同函数最终可能会具有相同的选择器. 当代理和执行合约为不
                 同的目的使用相同的存储槽时, 代理合约的调用意图因函数选择器冲突而发生偏移时, 可能意外触发实现合约中
                 的其他函数, 导致代理合约被错误升级至随机地址. 这种情况下, 系统的安全性取决于对实现合约地址的严格管理
                 和权限控制.


















                                                     图 7 clone() 函数

                  1.3   透明代理
                    2019  年, EIP-1967  提案  [54] 规定了透明代理  (transparent proxy), 旨在避免函数冲突, 并确保只有管理员   (admin)
                 才能调用升级函数. 这意味当普通用户调用代理合约时, 始终会执行实现合约中的函数, 而不会意外触发代理合约
                 的管理函数. 并且利用代理存储槽          (proxy storage slots) 的方法, 明确规定代理存储地址的位置, 确保代理不会向最
                 终用户暴露可能与实现合约冲突的函数. 函数调用对于用户来说是透明的. 图                        8  展示透明代理的设计结构.

                                                                         透明代理: EIP-1967
                                                                            代理存储槽
                                                   代理合约              调用地址        逻辑函数

                                       地址权限          other  fallback()  地址 V1   现实合约 V1
                               调用方       检查
                                                   proxy admin  upgrade()  地址 V1  现实合约 V2


                                                      图 8 透明代理

                    1) 透明代理   (transparent upgradeable proxy) 主要实现  3  个核心功能.
                    ● 构造函数: 初始化     admin  和实现合约地址.
                    ● fallback(): 回调函数, 将调用委托给实现合约, 并禁止        admin  调用.
                    ● upgrade(): 升级函数, 改变实现合约地址, 仅允许由        admin  调用.
                    2) 管理员合约    (proxy admin): 负责管理  admin  地址和升级功能.
                    3) EIP-1967 Proxy: 规定代理存储地址的特定位置, 并确保数据位置一致, 以防止存储冲突.
                    4) 实现合约   (implementation): 管理核心业务代码.
                    透明代理首先检查调用方的地址, 依据其权限将调用委托给底层逻辑代理. 如果调用方是                             other 地址, 则代理
                 合约只接受调用实现合约, 通过          delegatecall() 将调用转发给当前存储的实现合约地址. 实现合约在代理合约的上
                 下文中执行, 并返回结果给代理合约. 代理合约再将结果返回给用户; 如果调用方是代理的管理员, 则代理不会接
   38   39   40   41   42   43   44   45   46   47   48