美文网首页Solidity智能合约专题
Solidity合约代理模式的简单示例

Solidity合约代理模式的简单示例

作者: 梁帆 | 来源:发表于2022-11-08 16:52 被阅读0次

    一、概述

    这个合约示例中,我们有以下几个文件:

    Types.sol
    IProcessor.sol
    Processor.sol
    Proxy.sol
    Client.sol
    

    分别论述下文件的作用:
    Types.sol定义了一些基本类型,与业务逻辑无关;
    IProcessor.sol:关键合约,定义了Processor的接口;
    Processor.sol:关键合约,定义了实际对数据的逻辑操作;
    Proxy.sol:关键合约,定义了数据以及逻辑操作合约Processor的地址;
    Client.sol定义了用户操作Proxy合约的方法,免去手动将IProcessor赋予Proxy的过程。

    1.Types.sol

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    
    enum Gender {
        Male,
        Female
    }
    
    struct Student {
        string name;
        Gender gender;
        uint256 age;
    }
    

    2.IProcessor.sol

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    import {Gender} from "./Types.sol";
    
    interface IProcessor {
        function setStudentName(string memory) external;
        function setStudentGender(Gender) external;
        function setStudentAge(uint256) external;
    }
    

    3.Processor.sol

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    import "./IProcessor.sol";
    import {Gender, Student} from "./Types.sol";
    
    contract Processor is IProcessor {
        Student public student;
        address public processor;
    
        function setStudentName(string calldata _name) override external {
            student.name = _name;
        }
    
        function setStudentGender(Gender _gender) override external {
            student.gender = _gender;
        }
    
        function setStudentAge(uint256 _age) override external {
            student.age = _age;
        }
    }
    

    4.Proxy.sol

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    import "./IProcessor.sol";
    import {Student} from "./Types.sol";
    
    contract Proxy {
        Student public student;
        address public processor;
    
        function setProcessor(address _processor) external {
            processor = _processor;
        }
    
        fallback() external payable  {
            (bool success, bytes memory data) = processor.delegatecall(msg.data);
            require(
                success,
                "error"
            );
        }
    }
    

    5.Client.sol

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    import "./IProcessor.sol";
    import {Gender, Student} from "./Types.sol";
    
    contract Client {
        IProcessor ip;
    
        constructor(address _proxy) {
            ip = IProcessor(_proxy);
        }
    
        function setName(string calldata _name) external {
            ip.setStudentName(_name);
        } 
    
        function setGender(Gender _gender) external {
            ip.setStudentGender(_gender);
        }
    
        function setAge(uint256 _age) external {
            ip.setStudentAge(_age);
        }
    }
    

    我们用Client进行操作,比如说,执行setName函数,输入的参数为字符串Tom,接下来,就是触发IProcessor类型的代理合约Proxy去执行setStudentName,但事实上,代理合约中并没有setStudentName,因此会去执行fallback函数,fallback函数中有关键的delegatecall函数,它会委托Processor合约去执行setStudentName的函数逻辑,但是改变的是Proxy合约上的student值。这样就实现了数据逻辑的分离。下次如果我们需要升级逻辑处理合约就非常简单了——在Proxy中,使用setProcessor函数将旧的Processor合约替换成新的Processor合约即可。

    二、缺陷

    这个实现主要有两个缺陷。

    • 其一是Proxy中的fallback函数执行delegatecall后,有两个返回值,一个是bool类型的success,一个是bytes类型的data。这个示例中我们的Processor合约中的函数没有返回值,倒无所谓,如果有返回值的话,我们其实是需要返回给调用者的。
    • 其二是为了使得delegatecall的顺利执行,ProxyProcessor两个合约保持了相同的变量存储结构,但实际执行时Processor中的变量却仅仅是摆设,这样的设计就显得累赘,不够优雅。

    这两个问题其实都有解决方案,请看下一篇:《Solidity合约代理模式的几个技术技巧》

    相关文章

      网友评论

        本文标题:Solidity合约代理模式的简单示例

        本文链接:https://www.haomeiwen.com/subject/cyjntdtx.html