【从0学习Solidity】48. 透明代理

【从0学习Solidity】48. 透明代理

  • 博主简介:不写代码没饭吃,一名全栈领域的创作者,专注于研究互联网产品的解决方案和技术。熟悉云原生、微服务架构,分享一些项目实战经验以及前沿技术的见解。
  • 关注我们的主页,探索全栈开发,期待与您一起在移动开发的世界中,不断进步和创造!
  • 本文收录于 不写代码没饭吃 的学习汇报系列,大家有兴趣的可以看一看。
  • 欢迎访问我们的微信公众号:不写代码没饭吃,获取更多精彩内容、实用技巧、行业资讯等。您关注的是我们前进的动力!

这一讲,我们将介绍代理合约的选择器冲突(Selector Clash),以及这一问题的解决方案:透明代理(Transparent Proxy)。教学代码由OpenZeppelinTransparentUpgradeableProxy简化而成,不应用于生产。

选择器冲突

智能合约中,函数选择器(selector)是函数签名的哈希的前4个字节。例如mint(address account)的选择器为bytes4(keccak256("mint(address)")),也就是0x6a627842。更多关于选择器的内容见WTF Solidity极简教程第29讲:函数选择器

由于函数选择器仅有4个字节,范围很小,因此两个不同的函数可能会有相同的选择器,例如下面两个函数:

solidity 复制代码
// 选择器冲突的例子
contract Foo {
    function burn(uint256) external {}
    function collate_propagate_storage(bytes16) external {}
}

示例中,函数burn()collate_propagate_storage()的选择器都为0x42966c68,是一样的,这种情况被称为"选择器冲突"。在这种情况下,EVM无法通过函数选择器分辨用户调用哪个函数,因此该合约无法通过编译。

由于代理合约和逻辑合约是两个合约,就算他们之间存在"选择器冲突"也可以正常编译,这可能会导致很严重的安全事故。举个例子,如果逻辑合约的a函数和代理合约的升级函数的选择器相同,那么管理人就会在调用a函数的时候,将代理合约升级成一个黑洞合约,后果不堪设想。

目前,有两个可升级合约标准解决了这一问题:透明代理Transparent Proxy和通用可升级代理UUPS

透明代理

透明代理的逻辑非常简单:管理员可能会因为"函数选择器冲突",在调用逻辑合约的函数时,误调用代理合约的可升级函数。那么限制管理员的权限,不让他调用任何逻辑合约的函数,就能解决冲突:

  • 管理员变为工具人,仅能调用代理合约的可升级函数对合约升级,不能通过回调函数调用逻辑合约。
  • 其它用户不能调用可升级函数,但是可以调用逻辑合约的函数。

代理合约

这里的代理合约和第47讲的非常相近,只是fallback()函数限制了管理员地址的调用。

它包含3个变量:

  • implementation:逻辑合约地址。
  • admin:admin地址。
  • words:字符串,可以通过逻辑合约的函数改变。

它包含3个函数

  • 构造函数:初始化admin和逻辑合约地址。
  • fallback():回调函数,将调用委托给逻辑合约,不能由admin调用。
  • upgrade():升级函数,改变逻辑合约地址,只能由admin调用。
solidity 复制代码
// 透明可升级合约的教学代码,不要用于生产。
contract TransparentProxy {
    address implementation; // logic合约地址
    address admin; // 管理员
    string public words; // 字符串,可以通过逻辑合约的函数改变

    // 构造函数,初始化admin和逻辑合约地址
    constructor(address _implementation){
        admin = msg.sender;
        implementation = _implementation;
    }

    // fallback函数,将调用委托给逻辑合约
    // 不能被admin调用,避免选择器冲突引发意外
    fallback() external payable {
        require(msg.sender != admin);
        (bool success, bytes memory data) = implementation.delegatecall(msg.data);
    }

    // 升级函数,改变逻辑合约地址,只能由admin调用
    function upgrade(address newImplementation) external {
        if (msg.sender != admin) revert();
        implementation = newImplementation;
    }
}

逻辑合约

这里的新、旧逻辑合约与第47讲一样。逻辑合约包含3个状态变量,与保持代理合约一致,防止插槽冲突;包含一个函数foo(),旧逻辑合约会将words的值改为"old",新的会改为"new"

solidity 复制代码
// 旧逻辑合约
contract Logic1 {
    // 状态变量和proxy合约一致,防止插槽冲突
    address public implementation; 
    address public admin; 
    string public words; // 字符串,可以通过逻辑合约的函数改变

    // 改变proxy中状态变量,选择器: 0xc2985578
    function foo() public{
        words = "old";
    }
}

// 新逻辑合约
contract Logic2 {
    // 状态变量和proxy合约一致,防止插槽冲突
    address public implementation; 
    address public admin; 
    string public words; // 字符串,可以通过逻辑合约的函数改变

    // 改变proxy中状态变量,选择器:0xc2985578
    function foo() public{
        words = "new";
    }
}

Remix实现

  1. 部署新旧逻辑合约Logic1Logic2

  2. 部署透明代理合约TranparentProxy,将implementation地址指向把旧逻辑合约。

  3. 利用选择器0xc2985578,在代理合约中调用旧逻辑合约Logic1foo()函数。调用将失败,因为管理员不能调用逻辑合约。

  4. 切换新钱包,利用选择器0xc2985578,在代理合约中调用旧逻辑合约Logic1foo()函数,将words的值改为"old",调用将成功。

  5. 切换回管理员钱包,调用upgrade(),将implementation地址指向新逻辑合约Logic2

  6. 切换新钱包,利用选择器0xc2985578,在代理合约中调用新逻辑合约Logic2foo()函数,将words的值改为"new"

总结

这一讲,我们介绍了代理合约中的"选择器冲突",以及如何利用透明代理避免这个问题。透明代理的逻辑简单,通过限制管理员调用逻辑合约解决"选择器冲突"问题。它也有缺点,每次用户调用函数时,都会多一步是否为管理员的检查,消耗更多gas。但瑕不掩瑜,透明代理仍是大多数项目方选择的方案。

下一讲,我们会介绍省gas但是也更加复杂的通用可升级代理UUPS

如果这份博客对大家有帮助,希望各位给作者一个免费的点赞👍作为鼓励,并评论收藏一下⭐,谢谢大家!!!

制作不易,如果大家有什么疑问或给作者的意见,欢迎评论区留言。

相关推荐
MicroTech20251 小时前
微算法科技(NASDAQ :MLGO)量子测量区块链共识机制:保障数字资产安全高效存储与交易
科技·安全·区块链
区块链蓝海2 小时前
Ardor v2.6.0 正式发布:Nxt迁移完成,Ardor迈入多链协同新阶段
人工智能·区块链
MQLYES2 小时前
02-UniswapV1-源码篇
去中心化·区块链
devmoon3 小时前
快速了解兼容 Ethereum 的 JSON-RPC 接口
开发语言·网络·rpc·json·区块链·智能合约·polkadot
devmoon3 小时前
用Remix IDE在Polkadot Hub部署一个最基础的Solidity 合约(新手友好)
web3·区块链·智能合约·编译·remix·polkadot
暴躁小师兄数据学院4 小时前
【WEB3.0零基础转行笔记】Golang编程篇-第4讲:Go语言中的流程控制
开发语言·后端·golang·web3·区块链
devmoon4 小时前
使用 Remix IDE 在 Polkadot Hub 测试网部署 ERC-20 代币(新手完整实战教程)
web3·区块链·智能合约·solidity·remix·polkadot·erc-20
China_Yanhy4 小时前
入职 Web3 运维日记 · 第 7 日:消失的 5 万 U —— 归档节点与 Nginx 的智能分流
运维·区块链
ETFOption4 小时前
ETF期权实战手册:从策略构建到动态管理的完整流程
区块链
模型时代1 天前
Infosecurity Europe欧洲信息安全展将推出网络安全初创企业专区
安全·web安全·区块链