首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用高级委托调用自Byzantium以来可升级的合同

使用高级委托调用自Byzantium以来可升级的合同
EN

Ethereum用户
提问于 2018-01-26 16:31:27
回答 2查看 1.4K关注 0票数 9

由于Byzantium,我们可以通过使用returndatacopyreturndatasize程序集指令实现可升级的代理契约。这意味着我们不再需要注册返回类型和大小,比如在使用EtherRouter时。

我们知道如何构造代理契约的最可靠的方法是类似于齐柏林星代理,其中delegatecall是在程序集中生成的。但是,当将delegatecall作为一个高级别的可靠调用执行时,它似乎也起作用,代理契约回退函数看起来如下所示:

代码语言:javascript
复制
function () public {

    bool callSuccess = upgradableContractAddress.delegatecall(msg.data);

    if (callSuccess) {
        assembly {
            returndatacopy(0x0, 0x0, returndatasize)
            return(0x0, returndatasize)
        }
    } else {
        revert();
    }
}

这种方法(请参阅这里的整个代理)更加简洁,需要更少的组装知识才能理解。对于这种方法,我的最小测试似乎奏效了。

那么,在什么情况下,这种高层次的方法会不起作用呢?

如果没有,那么高级委托的编译后的字节码有多大可能会在不同的版本之间发生变化,从而打破了这些版本的这种方法?

EN

回答 2

Ethereum用户

发布于 2018-05-23 04:11:00

一个问题是从address 0开始将数据复制到内存中。这将适用于小于64个字节的返回大小,但此时将开始覆盖其他内存。

相反,你应该做一些更像

代码语言:javascript
复制
let m := mload(0x40)
returndatacopy(m, 0, returndatasize)
return(0, returndatasize)
票数 3
EN

Ethereum用户

发布于 2021-08-31 09:48:47

为了缓解@Tjaden提到的问题,什么 OpenZeppelin做了以下工作:

代码语言:javascript
复制
function functionDelegateCall(
    address target,
    bytes memory data,
    string memory errorMessage
) internal returns (bytes memory) {
    (bool success, bytes memory returndata) = target.delegatecall(data);
    if (success) {
        return returndata;
    } else {
        if (returndata.length > 0) {
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }

如果调用没有失败,则返回数据,就像正常情况下一样。否则,通过程序集还原,使还原原因冒泡。

小贴士:请参阅我在PRBProxy中的实现。

票数 1
EN
页面原文内容由Ethereum提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://ethereum.stackexchange.com/questions/37601

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档