如何在 Substrate 中拥有不可变的键值映射?
How to have immutable key-value map in Substrate?
我正在 substrate
中写一个 key: value
StorageMap
。我想让它不可变,以便在不存在但存在时写入密钥:
i) 如果这个值和存储的一样就OK
ii) 使交易无效。
我写了下面的runtime
代码:
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(())
}
}
}
official tutorial 谈到以下列方式改变密钥:
/// Mutate the value under a key.
fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: Storage>(key: &K, f: F, storage: &S) -> R;
那么,如何使我的 key:value
不可变?我应该自己写 StorageMap
吗?如果是,我应该将该代码放在哪里?
注意:我对基材和铁锈都是新手。
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.
您可以使用 exists
/contains_key
api on the storage item, and you should probably be even more explicit by using an Option
.
所以拿你写的代码,你会像这样修改它:
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(())
}
}
}
由于您在这里使用的是Option
,您还可以读取该值并检查它是Some(value)
还是None
,然后出错或继续。
你不能做的是 真正 使存储中的值不可变,这样所有代码都知道不要更改该值。您需要编写逻辑来提前检查该值是否存在,以免您更改它。
我正在 substrate
中写一个 key: value
StorageMap
。我想让它不可变,以便在不存在但存在时写入密钥:
i) 如果这个值和存储的一样就OK ii) 使交易无效。
我写了下面的runtime
代码:
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(())
}
}
}
official tutorial 谈到以下列方式改变密钥:
/// Mutate the value under a key.
fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: Storage>(key: &K, f: F, storage: &S) -> R;
那么,如何使我的 key:value
不可变?我应该自己写 StorageMap
吗?如果是,我应该将该代码放在哪里?
注意:我对基材和铁锈都是新手。
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.
您可以使用 exists
/contains_key
api on the storage item, and you should probably be even more explicit by using an Option
.
所以拿你写的代码,你会像这样修改它:
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(())
}
}
}
由于您在这里使用的是Option
,您还可以读取该值并检查它是Some(value)
还是None
,然后出错或继续。
你不能做的是 真正 使存储中的值不可变,这样所有代码都知道不要更改该值。您需要编写逻辑来提前检查该值是否存在,以免您更改它。