How error handling done in solidity ?
Writing robust contracts with proper error and exception management is one of the top best practices
Errors can occur at design time or runtime (Runtime errors, however, are more difficult to catch and generally occur while executing contracts) eg: out-of-gas errors, divide by zero errors, data type overflow errors, array-out-of-index errors
From version 4.10 of Solidity newer error handling constructs were introduced and throw statement was made obsolete and the new constructs are require, revert, assert statements.
**require **is used to validate inputs and conditions before execution.
require should be used to validate conditions such as:
inputs
conditions before execution
return values from calls to other functions
require statement takes in a single argument: a statement that evaluates to a true or false boolean value. If the evaluation of the statement is false , an exception is raised and execution is halted. The unused gas is returned to the caller and the state is reversed to the original
When to use require :
Can be used to validate the incoming parameters to a function , if a another function from another contract or a function with in the same contract called the incoming value can be checked using require
It can also be used to check the current state or variables before they are used
require should be used for values coming from the outside.
function deposit(uint _amount) public {
uint oldBalance = balance;
uint newBalance = balance + _amount;
// balance + _amount does not overflow if balance + _amount >= balance
require(newBalance >= oldBalance, "Overflow");
balance = newBalance;
assert(balance >= oldBalance);
}
revert is similar to require. See the code below for details. revert is best option when we have a lot of conditions check Hitting a revert statement means an exception is thrown, along with the return of unused gas, and reverts to its original state. **
function Validrange(uint range) public pure returns(uint){
if (range< 0 || range > 255){
revert();
}
return uint(range);
}
**assert ** It accepts a statement, that should then evaluate to either a true or false value. Based on that, the execution will either move on to the next statement or throw an exception. **The unused gas is not returned to the caller and instead the entire gas supply is consumed by assert **. The state is reversed to original
uint public uid = 123;
function assertH() public view returns(uint){
assert(uid == 123);
return uid;
}
Think of assert as working with runtime exceptions that you cannot predict.
The assert statement should be used when you think that a current state has become inconsistent and that execution should not continue.
assert should be used for validating the current state and condition of the function and contract before execution.
Assert should only be used to test for internal errors and to check invariants.