跳转至

回退函数

回退函数

回退函数是智能合约的特殊函数,没有名字、没有参数、没有返回值。

一个简单的回退函数

pragma solidity ^0.4.0;
contract simplefallback{
    function(){

    }
}

何时调用回退函数

合约调用未匹配函数签名

当程序找不到要调用的函数的时候就会调用默认的回退函数,但是 solidity 提供了编译器检查机制,不能直接通过 solidity 调用一个不存在的函数,所以我们通过 solidity 提供的底层函数 address.call() 来模拟一下

pragma solidity ^0.4.24;
contract ExecuteFallback{
  //回退事件,会把调用的数据打印出来
  event FallbackCalled(bytes data);
  //fallback函数,注意是没有名字的,没有参数,没有返回值的
  function() public{
    emit FallbackCalled(msg.data);
    //在这里返回的是functionNotExist()函数签名0x69774a91
  }
  //调用已存在函数的事件,会把调用的原始数据,请求参数打印出来
  event ExistFuncCalled(bytes data, uint256 para);
  //一个存在的函数
  function existFunc(uint256 para) public {
    emit ExistFuncCalled(msg.data, para);
  }
  // 模拟从外部对一个存在的函数发起一个调用,将直接调用函数
  function callExistFunc() public returns(bool){
    bytes4 funcIdentifier = bytes4(keccak256("existFunc(uint256)"));
    return address(this).call(funcIdentifier, uint256(1));
  }
  //模拟从外部对一个不存在的函数发起一个调用,由于匹配不到函数,将调用回退函数
  function callNonExistFunc() public returns(bool){
    bytes4 funcIdentifier = bytes4(keccak256("functionNotExist()"));
    return address(this).call(funcIdentifier);
  }
}
//来自博客:https://www.cnblogs.com/wanghui-garcia/p/9580464.html

点击 callExistFunc 会看到

image.png

这次点击 callNonExistFunc 看到对这次事件的描述是:"event": "FallbackCalled",而且要注意,这里 call 的返回值也为 true

image.png

一个没有定义一个回退函数的合约。如果接收 ether,会触发异常,并返还 ether(solidity v0.4.0开始)。所以合约要接收 ether,必须实现回退函数

合约调用未包含任何数据

当我们使用 address.send(ether to send) 函数向某个合约直接转账的时候,因为这个行为没有发送数据,所以也会调用 fallback 函数

pragma solidity ^0.4.24;
contract SendFallback{
  //fallback函数及其事件
  event FallbackTrigged(bytes data);
  function() public payable{//一定要声明为payable,否则send()执行结果将会始终为false
      emit FallbackTrigged(msg.data);  
  }
  //存入一些ether用于后面的测试
  function deposit() public payable{
  }
  //查询当前的余额
  function getBalance() public view returns(uint){
      return address(this).balance;
  }
  event SendEvent(address to, uint value, bool result);
  //使用send()发送ether,观察会触发fallback函数
  function sendEther() public{
      bool result = address(this).send(1);//从合约地址的余额中发送1wei给它自己,所以其balance不会变,只是会消耗msg.sender账户gas
      emit SendEvent(this, 1, result);
  }
}

先给合约一些钱

image.png

原文: https://www.yuque.com/hxfqg9/geth/cs95s3