解码自定义错误时为什么调用恢复

问题描述 投票:0回答:1

我有一个合约使用 try-catch 调用另一个合约,该合约会返回自定义错误。我正在使用 abi.decode 解码错误原因字节,但当我尝试解码时它正在恢复。

这是在 remix 中使用 Solidity 0.8.4。

代码是:

pragma solidity = 0.8.4;

error MyCustomError(uint256 value1, uint256 value2);

contract Reverter {
    function revertMe(uint256 valueA, uint256 valueB) public {
        revert MyCustomError(valueA, valueB);
    }
}

contract RevertCaller {
    Reverter reverter;
    event Revert(uint256 indexed value1, uint256 indexed value2);
    event LogBytes(bytes);
    
    constructor() {
        reverter = new Reverter();
    }

    function callRevert(uint256 valueA, uint256 valueB) public {
        try reverter.revertMe(valueA, valueB) {

        } catch (bytes memory reason) {
            emit Revert(valueA, valueB);
            emit LogBytes(reason);        

            (bytes4 errorSelector, uint256 value1, uint256 value2) = abi.decode(reason, (bytes4, uint256, uint256));

            if (errorSelector == MyCustomError.selector) {
                // Handle invalid amount error
                emit Revert(value1, value2);
            } else {
                emit Revert(0, 0);
            }
        }
    }
}

如果我注释掉 abi.decode 行并将一些其他值传递到事件中,它不会恢复。它也只能像这样解码选择器:

(bytes4 errorSelector) = abi.decode(reason, (bytes4));

但是我没有得到我想要使用的错误参数。

记录的原因(使用 LogBytes)是

0x64f2b82800000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000005

也许我错误地使用了abi.decode?

error-handling try-catch solidity remix custom-errors
1个回答
0
投票

您确实错误地使用了

abi.decode

错误的前 4 个字节的处理方式与函数选择器相同,并且它们的编码不遵循 ABI 规范。根据 ABI 规范,

bytes4
值应该用零填充,最多可达 32 个字节。这就是
abi.decode(reason, (bytes4))
起作用的原因,因为后面有零。然而,当您尝试解码完整字节时,解码器的数据中没有足够的填充,它只会恢复事务。

不幸的是,仍然没有好的方法可以在 Solidity 中进行自定义错误捕获。

以下汇编代码将实现所需的错误匹配行为:

callRevert(uint256 valueA, uint256 valueB) public {
    try reverter.revertMe(valueA, valueB) {
    } catch (bytes memory reason) {
        emit Revert(valueA, valueB);
        emit LogBytes(reason);        

        bytes4 errorSelector = bytes4(reason);
        uint256 value1;
        uint256 value2;

        assembly ("memory-safe") {
            value1 := mload(add(reason, 0x24))
            value2 := mload(add(reason, 0x44))
        }

        if (errorSelector == MyCustomError.selector) {
            // Handle invalid amount error
            emit Revert(value1, value2);
        } else {
            emit Revert(0, 0);
        }
    }
}

要使

bytes4 errorSelector = bytes4(reason)
投射正常工作,您需要更新到 Solidity 0.8.5。

© www.soinside.com 2019 - 2024. All rights reserved.