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

一个简单的回退函数

1
2
3
4
5
6
pragma solidity ^0.4.0;
contract simplefallback{
function(){

}
}

何时调用回退函数

合约调用未匹配函数签名

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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
image.png

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

image.png
image.png

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

合约调用未包含任何数据

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
image.png