Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs(30): 补充两种边缘情况 #851

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 46 additions & 5 deletions 30_TryCatch/TryCatch.sol
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

contract OnlyEven{
contract OnlyEven {
constructor(uint a){
require(a != 0, "invalid number");
assert(a != 1);
}

function onlyEven(uint256 b) external pure returns(bool success){
function onlyEven(uint256 b) external pure returns (bool success){
// 输入奇数时revert
require(b % 2 == 0, "Ups! Reverting");
success = true;
}
}

contract OnlyEven2 {
constructor(uint a){
require(a != 0, "invalid number");
assert(a != 1);
}

function onlyEven(uint256 b) external pure returns (uint256 success){
// 输入奇数时revert
require(b % 2 == 0, "Ups! Reverting");
success = b;
}
}

contract TryCatch {
// 成功event
event SuccessEvent();
Expand All @@ -27,12 +40,12 @@ contract TryCatch {
constructor() {
even = new OnlyEven(2);
}

// 在external call中使用try-catch
// execute(0)会成功并释放`SuccessEvent`
// execute(1)会失败并释放`CatchEvent`
function execute(uint amount) external returns (bool success) {
try even.onlyEven(amount) returns(bool _success){
try even.onlyEven(amount) returns (bool _success){
// call成功的情况下
emit SuccessEvent();
return _success;
Expand All @@ -47,7 +60,7 @@ contract TryCatch {
// executeNew(1)会失败并释放`CatchByte`
// executeNew(2)会成功并释放`SuccessEvent`
function executeNew(uint a) external returns (bool success) {
try new OnlyEven(a) returns(OnlyEven _even){
try new OnlyEven(a) returns (OnlyEven _even){
// call成功的情况下
emit SuccessEvent();
success = _even.onlyEven(a);
Expand All @@ -59,4 +72,32 @@ contract TryCatch {
emit CatchByte(reason);
}
}

// 调用非合约的方法,这里无法被try-catch捕获,会导致revert
function executeRevert() external {
try OnlyEven(address(0)).onlyEven(1){
// call成功的情况下
emit SuccessEvent();
} catch Error(string memory reason){
// catch revert("reasonString") 和 require(false, "reasonString")
emit CatchEvent(reason);
} catch (bytes memory reason){
// catch失败的assert assert失败的错误类型是Panic(uint256) 不是Error(string)类型 故会进入该分支
emit CatchByte(reason);
}
}

// 调用返回值不一致的方法,这里无法被try-catch捕获,会导致revert
function executeRevert2() external returns (bool success){
address onlyEven2 = address(new OnlyEven2(2));
uint256 amount = 2;
try OnlyEven(onlyEven2).onlyEven(amount) returns (bool _success){
// call成功的情况下
emit SuccessEvent();
return _success;
} catch Error(string memory reason){
// call不成功的情况下
emit CatchEvent(reason);
}
}
}
40 changes: 40 additions & 0 deletions 30_TryCatch/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,46 @@ function executeNew(uint a) external returns (bool success) {

![30-5](./img/30-5.png)

但是`try-catch`并不是万能的,有两种情况`try-catch`也无法捕获

1.在try中调用的非合约地址的方法,即codesize为0
```solidity
// 调用非合约地址的方法,这里无法被try-catch捕获,会导致revert
function executeRevert() external {
//将0地址强制转换为OnlyEven合约地址,模拟调用非合约地址的方法
try OnlyEven(address(0)).onlyEven(1){
// call成功的情况下
emit SuccessEvent();
} catch Error(string memory reason){
// catch revert("reasonString") 和 require(false, "reasonString")
emit CatchEvent(reason);
} catch (bytes memory reason){
// catch失败的assert assert失败的错误类型是Panic(uint256) 不是Error(string)类型 故会进入该分支
emit CatchByte(reason);
}
}
```
![30-6](./img/30-6.png)

2.函数返回值与期望的不一致
```solidity
// 调用返回值不一致的方法,这里无法被try-catch捕获,会导致revert
function executeRevert2() external returns (bool success){
address onlyEven2 = address(new OnlyEven2(2));
uint256 amount = 2;
//OnlyEven2的返回值是 uint256,而这里期望的是bool,会导致revert
try OnlyEven(onlyEven2).onlyEven(amount) returns (bool _success){
// call成功的情况下
emit SuccessEvent();
return _success;
} catch Error(string memory reason){
// call不成功的情况下
emit CatchEvent(reason);
}
}
```
![30-7](./img/30-7.png)

## 总结

在这一讲,我们介绍了如何在`Solidity`使用`try-catch`来处理智能合约运行中的异常:
Expand Down