首页 > 解决方案 > solidity delegatecall 在另一个合约中不起作用

问题描述

我正在尝试一些代码来查找调用和委托调用之间的差异。而且我发现 delegatecall 和 call 都不起作用。

pragma solidity ^0.4.23;


contract A{
    address public owner;  // storage
    uint256 counter = 0;

    event addrLog(address _addr, uint256 _counter);

    function getaddr() public returns(address addr){
        addr = address(this);
        owner = addr;


        emit addrLog(owner, ++counter);
    }
}

contract B{
    address public owner; // storage, will used A.owner if A is existed.
    // see a strange usage, I tried bug got compile err, not understanded.
    // address public testAddr = address of A;

    address public testAddr;
    bytes4 public messageId;
    bool public r1;
    bool public r2;

    constructor(address _addressOfCalltest) public {
        testAddr = _addressOfCalltest;
    }

    function testCall() public returns(bool){
        messageId = bytes4(keccak256("getaddr()"));
        return testAddr.call(messageId);
    }

    function testDelegatecall() public returns(bool){
        messageId = bytes4(keccak256("getaddr()"));
        return testAddr.delegatecall(messageId);
    }

    function run() public{
        r1 = testCall();
        r2 = testDelegatecall();
    }
}

当我在 JS VM 中调用 A.getaddr() 时,日志是好的,它工作正常。

[
    {
        "from": "0xef55bfac4228981e850936aaf042951f7b146e41",
        "topic": "0xff2a5ce99c57a44e471dfcb9313f2cc369b2abf37959acedfbeb720f304545e6",
        "event": "addrLog",
        "args": {
            "0": "0xef55BfAc4228981E850936AAf042951F7b146e41",
            "1": "2",
            "_addr": "0xef55BfAc4228981E850936AAf042951F7b146e41",
            "_counter": "2",
            "length": 2
        }
    }
]

但是,当我调用 B.run() 或 B.testCall() 或 B.testDelegatecall() 时,它不起作用,日志为空:

[]

并且 r1、r2 都从 false 变为 true,这意味着 testAddr.call(messageId) 和 testAddr.delegatecall(messageId) 都运行成功。所以我的问题是为什么 log 为 null,这意味着 getaddr() 实际上没有被调用?</p>

标签: solidity

解决方案


testCall()工作正常。有一些问题testDelegatecall()。要了解为什么您首先需要了解其delegatecall工作原理。这是solidity文档中所说的:

存在一个消息调用的特殊变体,称为委托调用, 它与消息调用相同,除了目标地址处的代码在调用合约的上下文中执行msg.sender并且msg.value不更改它们的值这一事实。

这意味着当您使用.delegatecall() getaddr()时将作为Contract B函数的一部分调用。但是_counter合约 B 中的不退出log将包含一些垃圾值_counter


推荐阅读