Как иметь неизменную карту ключ-значение в субстрате? - PullRequest
0 голосов
/ 22 февраля 2020

Я пишу 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 Ответ

1 голос
/ 22 февраля 2020

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

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

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

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

...