I am writing a key: value
StorageMap
in substrate
. I want to make it immutable such that a key is written if non-existent but if it exists:
i) if the value is the same as stored, alright ii) invalidate the transaction.
I have written the following runtime
code :
use support::{decl_module, decl_storage, dispatch::Result, StorageMap};
use system::ensure_signed;
pub trait Trait: balances::Trait {}
decl_storage! {
trait Store for Module<T: Trait> as KittyStorage {
Value: map u64 => T::AccountId;
}
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn set_value(origin, value: u64) -> Result {
let sender = ensure_signed(origin)?;
<Value<T>>::insert(value, sender);
Ok(())
}
}
}
The official tutorial talks about mutating the key in the following manner:
/// Mutate the value under a key.
fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: Storage>(key: &K, f: F, storage: &S) -> R;
So, how do I make my key:value
immutable? Should I write my own StorageMap
? If yes, where should I place that code?
Note: I am new to both substrate and rust.
I want to make it immutable such that a key is written if non-existent but if it exists:
i) if the value is the same as stored, alright ii) invalidate the transaction.
You can use the exists
/contains_key
api on the storage item, and you should probably be even more explicit by using an Option
.
So taking the code you have written, you would modify it like so:
use support::{decl_module, decl_storage, dispatch::Result, ensure, StorageMap};
use system::ensure_signed;
pub trait Trait: balances::Trait {}
decl_storage! {
trait Store for Module<T: Trait> as KittyStorage {
Value: map u64 => Option<T::AccountId>;
}
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn set_value(origin, value: u64) -> Result {
let sender = ensure_signed(origin)?;
ensure!(!<Value<T>>::contains_key(value), "key already exists");
<Value<T>>::insert(value, sender);
Ok(())
}
}
}
Since you are using an Option
here, you can also read the value and check if it is Some(value)
or None
and then error or continue as a result.
What you cannot do is truly make the value immutable in storage such that all code would know not to change the value. You would need to write logic to check ahead of time the value is there so that you don't change it.