Avoid Unwrap Usage Inside Runtime
Severity: Critical
Description
Using unwrap()
and similar methods for error handling in Substrate runtime/pallet code can lead to runtime panics, which are particularly dangerous in a decentralized network. Such panics can cause block production to halt, disrupt the network, and compromise the reliability of the blockchain. Explicit error handling ensures more robust and predictable behavior, safeguarding the system against unexpected conditions in production environments.
What should be avoided
The following example demonstrates how using unwrap()
for error handling can result in runtime panics, which are neither user-friendly nor safe in a blockchain context:
#![allow(unused)] fn main() { // Create an empty vector: [ ] let my_data = Vec::<u32>::new(); // Potential panic if index 0 is empty let value = my_data.get(0).unwrap(); // Same error, with implicit unwrapping let value = my_data[0]; }
In a Substrate runtime, such panics could stop block production, making the entire chain unrecoverable or in the best case provoking downtimes.
Best practice
Handle errors explicitly by using Result
and provide descriptive error messages:
#![allow(unused)] fn main() { #[pallet::error] pub enum Error<T> { // Custom error MyError, } let my_data = Vec::<u32>::new(); // Gracefully handling the error let value = my_data.get(0).ok_or(Error::<T>::MyError)?; }
In this example:
- The code safely handles the case where
my_data.get(0)
might beNone
, allowing for graceful error handling and reducing the risk of panics.