Ethereum

Solidity 0.6.x features: try/catch statement

The try/catch syntax introduced in 0.6.0 is arguably the most important leap in error dealing with capabilities in Solidity, since motive strings for revert and require had been launched in v0.4.22. Each attempt and catch have been reserved key phrases since v0.5.9 and now we are able to use them to deal with failures in exterior perform calls with out rolling again the whole transaction (state modifications within the known as perform are nonetheless rolled again, however the ones within the calling perform will not be).

We’re transferring one step away from the purist “all-or-nothing” strategy in a transaction lifecycle, which falls wanting sensible behaviour we regularly need.

Dealing with exterior name failures

The try/catch statement means that you can react on failed exterior calls and contract creation calls, so you can’t use it for inner perform calls. Word that to wrap a public perform name inside the identical contract with try/catch, it may be made exterior by calling the perform with this..

The instance beneath demonstrates how try/catch is utilized in a manufacturing facility sample the place contract creation would possibly fail. The next CharitySplitter contract requires a compulsory deal with property _owner in its constructor.

pragma solidity ^0.6.1;

contract CharitySplitter {
    deal with public proprietor;
    constructor (deal with _owner) public {
        require(_owner != deal with(0), "no-owner-provided");
        proprietor = _owner;
    }
}

There’s a manufacturing facility contract — CharitySplitterFactory which is used to create and handle situations of CharitySplitter. Within the manufacturing facility we are able to wrap the new CharitySplitter(charityOwner) in a try/catch as a failsafe for when that constructor would possibly fail due to an empty charityOwner being handed.

pragma solidity ^0.6.1;
import "./CharitySplitter.sol";
contract CharitySplitterFactory {
    mapping (deal with => CharitySplitter) public charitySplitters;
    uint public errorCount;
    occasion ErrorHandled(string motive);
    occasion ErrorNotHandled(bytes motive);
    perform createCharitySplitter(deal with charityOwner) public {
        attempt new CharitySplitter(charityOwner)
            returns (CharitySplitter newCharitySplitter)
        {
            charitySplitters[msg.sender] = newCharitySplitter;
        } catch {
            errorCount++;
        }
    }
}

Word that with try/catch, solely exceptions taking place contained in the exterior name itself are caught. Errors contained in the expression will not be caught, for instance if the enter parameter for the new CharitySplitter is itself a part of an inner name, any errors it raises won’t be caught. Pattern demonstrating this behaviour is the modified createCharitySplitter perform. Right here the CharitySplitter constructor enter parameter is retrieved dynamically from one other perform — getCharityOwner. If that perform reverts, on this instance with “revert-required-for-testing”, that won’t be caught within the try/catch statement.

perform createCharitySplitter(deal with _charityOwner) public {
    attempt new CharitySplitter(getCharityOwner(_charityOwner, false))
        returns (CharitySplitter newCharitySplitter)
    {
        charitySplitters[msg.sender] = newCharitySplitter;
    } catch (bytes reminiscence motive) {
        ...
    }
}
perform getCharityOwner(deal with _charityOwner, bool _toPass)
        inner returns (deal with) {
    require(_toPass, "revert-required-for-testing");
    return _charityOwner;
}

Retrieving the error message

We will additional prolong the try/catch logic within the createCharitySplitter perform to retrieve the error message if one was emitted by a failing revert or require and emit it in an occasion. There are two methods to realize this:

1. Utilizing catch Error(string reminiscence motive)

perform createCharitySplitter(deal with _charityOwner) public {
    attempt new CharitySplitter(_charityOwner) returns (CharitySplitter newCharitySplitter)
    {
        charitySplitters[msg.sender] = newCharitySplitter;
    }
    catch Error(string reminiscence motive)
    {
        errorCount++;
        CharitySplitter newCharitySplitter = new
            CharitySplitter(msg.sender);
        charitySplitters[msg.sender] = newCharitySplitter;
        // Emitting the error in occasion
        emit ErrorHandled(motive);
    }
    catch
    {
        errorCount++;
    }
}

Which emits the next occasion on a failed constructor require error:

CharitySplitterFactory.ErrorHandled(
    motive: 'no-owner-provided' (sort: string)
)

2. Utilizing catch (bytes reminiscence motive)

perform createCharitySplitter(deal with charityOwner) public {
    attempt new CharitySplitter(charityOwner)
        returns (CharitySplitter newCharitySplitter)
    {
        charitySplitters[msg.sender] = newCharitySplitter;
    }
    catch (bytes reminiscence motive) {
        errorCount++;
        emit ErrorNotHandled(motive);
    }
}

Which emits the next occasion on a failed constructor require error:

CharitySplitterFactory.ErrorNotHandled(
  motive: hex'08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000116e6f2d6f776e65722d70726f7669646564000000000000000000000000000000' (sort: bytes)

The above two strategies for retrieving the error string produce an identical consequence. The distinction is that the second technique doesn’t ABI-decode the error string. The benefit of the second technique is that it is usually executed if ABI decoding the error string fails or if no motive was offered.

Future plans

There are plans to launch assist for error sorts which means we can declare errors in an identical approach to occasions permitting us to catch completely different sort of errors, for instance:

catch CustomErrorA(uint data1) {}
catch CustomErrorB(uint[] reminiscence data2) {}
catch {}

DailyBlockchain.News Admin

Our Mission is to bridge the knowledge gap and foster an informed blockchain community by presenting clear, concise, and reliable information every single day. Join us on this exciting journey into the future of finance, technology, and beyond. Whether you’re a blockchain novice or an enthusiast, DailyBlockchain.news is here for you.
Back to top button