前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Solidity:call 和 delegatecall

Solidity:call 和 delegatecall

作者头像
孟斯特
发布2024-05-28 20:45:14
1580
发布2024-05-28 20:45:14
举报
文章被收录于专栏:code人生

在Solidity中,calldelegatecall是两种用于在合约之间进行交互的低级函数。它们都可以调用合约的函数,但是它们的工作方式和用途有所不同。

call

call是一种低级函数,它可以调用合约的任何函数,包括非公开的函数。call函数接收一个函数签名和一些参数,然后在目标合约上执行该函数。call函数会创建一个新的执行环境,这意味着调用的函数有自己的thismsg.sender

delegatecall

delegatecallcall类似,也可以调用合约的任何函数。然而,delegatecall不会创建一个新的执行环境,而是在调用合约的上下文中执行函数。这意味着,被调用的函数可以访问和修改调用合约的存储。

delegatecall在升级合约和实现库函数等场景中非常有用,因为它允许一个合约借用另一个合约的代码,同时保持自己的状态。

对比

calldelegatecall函数在Solidity中都用于调用合约的函数,但它们在执行方式和用途上有一些关键的区别:

1.执行上下文:当使用call函数时,被调用的函数在被调用合约的上下文中执行,这意味着它有自己的thismsg.sender。而delegatecall函数则在调用合约的上下文中执行被调用的函数,这意味着thismsg.sender在被调用函数中与调用合约相同。2.状态存储call函数在执行时不会改变调用合约的状态,它只会改变被调用合约的状态。而delegatecall函数则可以改变调用合约的状态,因为它在调用合约的上下文中执行。3.用途call函数通常用于调用其他合约的函数,而delegatecall函数则常用于实现合约的升级和库函数。delegatecall允许一个合约借用另一个合约的代码,同时保持自己的状态,这在升级合约和实现库函数等场景中非常有用。

使用场景

在Solidity中,calldelegatecall函数都用于在合约之间进行交互,但它们的使用场景有所不同。

使用call的情况

call函数通常用于调用另一个合约的函数。当你需要在一个合约中调用另一个合约的函数,并且不需要改变当前合约的状态时,可以使用call函数。例如,你可能需要查询另一个合约的状态,或者调用其某个函数来执行某些操作。

使用delegatecall的情况

delegatecall函数通常用于实现合约的升级和库函数。当你需要在一个合约中调用另一个合约的函数,并且需要改变当前合约的状态时,可以使用delegatecall函数。delegatecall允许一个合约在其自身的上下文中执行另一个合约的代码,这意味着被调用的函数可以访问和修改调用合约的存储。

需要注意的是,calldelegatecall都是低级函数,使用它们需要非常小心,因为它们可能会导致意想不到的副作用。例如,如果被调用的函数抛出异常,那么整个交易都会被回滚。此外,如果你不正确地使用delegatecall,你可能会无意中修改合约的状态。因此,除非你完全理解它们的工作原理,否则最好避免直接使用它们。

不适用场景

在Solidity中,calldelegatecall都是低级函数,虽然它们在某些情况下非常有用,但在以下情况下应该避免直接使用它们:

1.安全性问题calldelegatecall都可能导致重入攻击。如果在调用外部合约后还有未完成的工作(例如,更新状态变量),并且未采取适当的防护措施,那么被调用的合约可能会再次调用原始合约,从而导致重入攻击。

2.异常处理calldelegatecall不会自动处理被调用函数抛出的异常。如果被调用的函数抛出异常,那么整个交易都会被回滚,除非你在调用calldelegatecall时进行了检查。

3.状态修改delegatecall可以修改调用合约的状态,这在某些情况下可能是有用的,但如果不小心使用,可能会导致意外的结果。例如,如果你不小心调用了一个会修改你不希望修改的状态变量的函数,那么可能会导致合约的状态被破坏。

4.函数可见性calldelegatecall可以调用任何函数,包括非公开的函数。这可能会导致意外的行为,如果你不小心调用了一个你不应该调用的函数,可能会导致问题。

call调用示例

代码语言:javascript
复制
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

// 接收者合约
contract Receiver {
    // 定义一个事件,当接收到资金时触发
    event Received(address caller, uint256 amount, string message);

    // 接收函数,用于接收ETH
    receive() external payable {}

    // fallback函数,当调用不存在的函数时触发
    fallback() external payable {
        emit Received(msg.sender, msg.value, "Fallback was called");
    }

    // foo函数,接收一个消息和一个数值,返回数值加一
    function foo(string memory _message, uint256 _x)
        public
        payable
        returns (uint256)
    {
        emit Received(msg.sender, msg.value, _message);

        return _x + 1;
    }
}

// 调用者合约
contract Caller {
    // 定义一个事件,当接收到响应时触发
    event Response(bool success, bytes data);

    // 假设调用者合约不知道接收者合约的源代码,
    // 但我们知道接收者合约的地址和要调用的函数。
    function testCallFoo(address payable _addr) public payable {
        // 你可以发送以太币并指定自定义的gas数量
        (bool success, bytes memory data) = _addr.call{
            value: msg.value,
            gas: 5000
        }(abi.encodeWithSignature("foo(string,uint256)", "call foo", 123));

        emit Response(success, data);
    }

    // 调用一个不存在的函数会触发fallback函数。
    function testCallDoesNotExist(address payable _addr) public payable {
        (bool success, bytes memory data) = _addr.call{value: msg.value}(
            abi.encodeWithSignature("doesNotExist()")
        );

        emit Response(success, data);
    }
}

声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)[1]进行许可,使用时请注明出处。 Author: mengbin[2] blog: mengbin[3] Github: mengbin92[4] cnblogs: 恋水无意[5] 腾讯云开发者社区:孟斯特[6]

References

[1] 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0): https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh [2] mengbin: mengbin1992@outlook.com [3] mengbin: https://mengbin.top [4] mengbin92: https://mengbin92.github.io/ [5] 恋水无意: https://www.cnblogs.com/lianshuiwuyi/ [6] 孟斯特: https://cloud.tencent.com/developer/user/6649301

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-05-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 孟斯特 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • call
  • delegatecall
  • 对比
  • 使用场景
  • 不适用场景
  • call调用示例
    • References
    相关产品与服务
    对象存储
    对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档