If there is one "rule of thumb" in developing in a runtime environment, is to avoid runtime
panics at all costs. With the premise that a blockchain should never cease to operate, abusing the
panic!(king) in Rust should never be used.
Avoiding runtime panics - Defensive Programming
Avoiding runtime panics is done by implementing some concepts of defensive programming. Here is a checklist of some common things to avoid and do in order to avoid panicking:
- Account for any and all edge cases in terms of what could panic.
- Do not use
- Do not use
- Handle all possible
Errvalues with proper error handling.
- When indexing collections, use
get()and handle appropriately.
- Mathematically impossible operations, such as dividing by zero, or overflow scenarios.
In some cases, using
unwrap_or_default() is appropriate, but only if a
exists for that particular type. Generally, you do not want to throw errors, rather you want to
log and return them.
Keep in mind that logging has a computational cost in the runtime environment.
Using safe arithmetic
In the previous modules, we used a function -
checked_add(). This is part of defensive
programming, as we even negate the chance of an overflow of an integer. Substrate provides a number
of ways to handle not only adding or subtracting numbers, but also floating point numbers (and
Accounting for all errors
As mentioned, every single error should be accounted for - even if logically, that error cannot be
reached. This is part of ensuring that any functions that can panic
unwrap(), have even a chance
to panic. Whether it's for casting to a different type, user-induced errors, or the like - all
branched paths should be covered.