如何在 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,然后出错或继续。

你不能做的是 真正 使存储中的值不可变,这样所有代码都知道不要更改该值。您需要编写逻辑来提前检查该值是否存在,以免您更改它。