Как иметь неизменяемую карту "ключ-значение" в Substrate?

Я пишу key: value StorageMap в substrate. Я хочу сделать его неизменным, чтобы ключ записывался, если он не существует, но если он существует:

i) если значение совпадает с сохраненным, хорошо 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(())
        }
    }
}

В официальном руководстве говорится о мутации ключа следующим образом:

/// 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? Если да, то где мне разместить этот код?

Примечание: я новичок как в подложке, так и в ржавчине.

1 ответ

Решение

Я хочу сделать его неизменным, чтобы ключ записывался, если он не существует, но если он существует:

i) если значение совпадает с сохраненным, хорошо ii) аннулировать транзакцию.

Вы можете использовать exists/contains_key api для элемента хранилища, и вам, вероятно, следует быть еще более явным, используя 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 а затем ошибка или продолжение в результате.

То, что вы не можете сделать, это действительно сделать неизменяемое значение в памяти таким образом, что весь код будет знать, чтобы не изменить значение. Вам нужно будет написать логику, чтобы заранее проверять наличие значения, чтобы вы не меняли его.

Другие вопросы по тегам