Skip to main content

Lazy values not set

Description

Exploit Scenario

Consider the following contract:

    #[ink(storage)]
pub struct Contract {
mapping: Mapping<AccountId, u64>,
}
impl Contract {
/* --- snip --- */
#[ink(message)]
pub fn sum(&mut self, value: u64) -> Result<(), Error> {
let key = self.env().caller();
let mut _val = self.mapping.get(key).unwrap_or_default();
_val += value;
Ok(())
}
/* --- snip --- */
}

In this case, when you .get(...) a value from a Lazy storage field, you probably want to mutate it. The values are not automatically flushed to storage, so you need to .set(...) it.

Remediation

Use the .set(...) or .insert(...) method after using .get(...) to flush the new value to storage.

    #[ink(storage)]
pub struct Contract {
mapping: Mapping<AccountId, u64>,
}
impl Contract {
/* --- snip --- */
#[ink(message)]
pub fn sum(&mut self, value: u64) -> Result<(), Error> {
let key = self.env().caller();
let mut _val = self.mapping.get(key).unwrap_or_default();
_val += value;
self.mapping.insert(key, value);
Ok(())
}
/* --- snip --- */
}

Known Issues

If you have a .get(...) function that you don't mutate (e.g., used as a const value), this detector triggers, if you want to ignore the lint you could add #[allow(lazy_values_not_set)] immediately before the function definition.