• Solitidy - fallback 回退函数 - 2种触发执行方式


    fallback简介

    详情参考: 合约 — Solidity develop 文档

    fallback函数是合约中的一个未命名函数,没有参数且没有返回值。

    fallback执行条件:

    1. 如果在一个合约的调用中,没有其他函数与给定的函数标识符匹配时(或没有提供调用数据),fallback函数会被执行;
    2. 当合约收到以太币时,fallback函数会被执行。 

    以下针对2种执行方式进行示例展示,源码也可以参见:smartcontract/Fallback at main · tracyzhang1998/smartcontract · GitHub

    执行条件1 

    如果在一个合约的调用中,没有其他函数与给定的函数标识符匹配时(或没有提供调用数据),fallback函数会被执行

    测试合约代码

    1. // SPDX-License-Identifier: MIT
    2. pragma solidity ^0.8.7;
    3. //基合约实现
    4. contract TestFallback {
    5. string message;
    6. //构造函数,初始化状态变量message
    7. constructor() {
    8. message = "hello";
    9. }
    10. fallback() external {
    11. message = "fallback";
    12. }
    13. //调用此合约中不存在的函数
    14. function testFallback() external returns (bytes memory) {
    15. // 调用不存在的函数getMsgNew()
    16. bytes memory method = abi.encodeWithSignature("getMsgNew()");
    17. (bool success, bytes memory returnData) = address(this).call(method);
    18. require(success, "get fail");
    19. return returnData;
    20. }
    21. //调用此合约中已存在函数,但是没有传递参数
    22. function testFallbackWithNoParam() external returns (bytes memory) {
    23. // 调用已存在的函数setMsg(),未传递参数
    24. bytes memory method = abi.encodeWithSignature("setMsg()");
    25. (bool success, bytes memory returnData) = address(this).call(method);
    26. require(success, "set fail");
    27. return returnData;
    28. }
    29. function getMsg() external view returns (string memory) {
    30. return message;
    31. }
    32. function setMsg(string memory _message) external {
    33. message = _message;
    34. }
    35. }

    测试步骤与结果

    (1)调用一个不存在的函数

    0、部署合约,调用getMsg函数查看状态变量初始值为"hello"

    1、调用函数testFallback,调用一个不存在的函数

    2、调用getMsg函数查看状态变量已修改fallback函数中设置的"fallback"了

    (2)调用一个已存在的函数但没传递参数 

    1、调用setMsg函数设置状态变量初始值为"hello"

    2、调用函数testFallbackWithNoParam,调用一个已存在的函数但没传递参数

    3、调用getMsg函数查看状态变量已修改fallback函数中设置的"fallback"了

    执行条件2

    当合约收到以太币时,fallback函数会被执行,为了接收以太币,fallback 函数必须标记为 payable。 如果不存在这样的函数,则合约不能通过常规交易接收以太币。

    测试合约代码

    1. // SPDX-License-Identifier: MIT
    2. pragma solidity ^0.8.7;
    3. // 包含fallback函数的合约,合约账户能够接收到其它合约转的以太币
    4. contract TestFallback {
    5. string message;
    6. //构造函数,初始化状态变量message,同时可向合约账户存款
    7. constructor() payable {
    8. message = "hello";
    9. }
    10. //回退函数,能够为此合约账户接收以太币
    11. fallback() external payable {
    12. }
    13. //存款,若部署时忘记存款,可直接调用此函数向合约账户存款
    14. function deposit() external payable {
    15. }
    16. //发送以太
    17. function sendEther(address _addr) external {
    18. bool result = payable(_addr).send(2);
    19. require(result, "send fail");
    20. }
    21. //查看合约账户余额
    22. function getContractBalance() external view returns (uint256) {
    23. return address(this).balance;
    24. }
    25. }
    26. // 不包含fallback函数的合约
    27. contract TestWithoutFallback {
    28. //构造函数,初始化时可向合约账户存款
    29. constructor() payable{
    30. }
    31. //存款,若部署时忘记存款,可直接调用此函数向合约账户存款
    32. function deposit() external payable {
    33. }
    34. //发送以太
    35. function sendEther(address _addr) external returns (bool) {
    36. bool result = payable(_addr).send(2);
    37. return result;
    38. }
    39. //查看合约账户余额
    40. function getContractBalance() external view returns (uint256) {
    41. return address(this).balance;
    42. }
    43. }

    部署

    部署时可直接向合约转20Wei,若部署时忘记转,则可使用合约中的deposit存款函数向合约转20Wei,如下图所示:

    测试步骤与结果

    (1)使用未含fallback合约函数向有fabllback合约发送以太

    1. 调用未含fallback合约(TestWithoutFallback)中的发送以太函数sendEther,参数为含fallback合约(TestFallback)地址,转2Wei;
    2. 查看TestWithoutFallback合约账户余额,发现少了2Wei,当前为18Wei了,证明转账成功;
    3. 查看TestFallback合约账户余额,发现多了2Wei,当前为22Wei,证明接收成功,合约账户能够接收以太,是因为合约中含有fallback函数(且为payable)。

    (2)使用含fallback合约函数向未含fabllback合约发送以太

    使用含fallback合约函数向未含fabllback合约发送以太,发现转账失败,报错了(如下图所示),即没有fallback函数的合约不能接收以币。官网文档解释如下:

    一个没有定义 fallback 函数的合约,直接接收以太币(没有函数调用,即使用 send 或 transfer)会抛出一个异常, 并返还以太币(在 Solidity v0.4.0 之前行为会有所不同)。所以如果你想让你的合约接收以太币,必须实现 fallback 函数。

    遇到的问题

    在测试时,想通过查看状态变量message看是否发生调用fallback,在fallback函数中对message状态变量修改值,如下所示:

        fallback() external payable {

            message = "fallback";

        }

    测试使用未含fallback合约函数向有fabllback合约发送以太,如上面测试结果应该转账成功,但是此时转账会失败,如下图所示:

    最终去除了fallback函数中设置message状态变量,函数体未包含任何内容,转账成功,与第(1)步测试结果相同。

        fallback() external payable {

        }

  • 相关阅读:
    【MATLAB教程案例14】基于ACO蚁群优化算法的函数极值计算matlab仿真及其他应用
    进程间的通信终章之【消息队列,信号量,共享内存】
    VC中怎么进行结构体数组的初始化?
    Apache Doris 系列: 入门篇-创建数据表
    C++基础教程(转载)
    老师设计的库CRC计算
    SpringBoot集成MyBatis
    leetcode 刷题 log day 50(继续股票专题
    Nginx反向代理和负载均衡
    Agile Development
  • 原文地址:https://blog.csdn.net/ling1998/article/details/125488149