Как использовать PalletB для сохранения записи из PalletA, не зная, что PalletA ничего о внутренних деталях сохранения субстрата и ржавчины

Я хочу сохранить запись из PalletA в PalletB, просто передав необработанные данные и дождавшись возврата.

Я пробовал следующее:

// ./PalletB/lib.rs

pub trait PutInStorage {
    fn put_rule_in_storage(value: u32);
}

impl<T: Trait> PutInStorage for Module<T> {
    fn put_rule_in_storage(value: u32) {
        SimpleCounter::put(value);
    }
}

затем в

// ./PalletA/lib.rs
use palletB::{PutInStorage, Trait as PalletBTrait};

///The pallet's configuration trait.
pub trait Trait: system::Trait + PalletBTrait {
    /// The overarching event type.
    type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
    type ExternalStorage: PutInStorage;
}

затем я добавил определение в среду выполнения следующим образом:

// ./runtime/lib.rs
// near the construct_runtime macro

impl palletA::Trait for Runtime {
    type Event = Event;
    type ExternalStorage = palletB::Module<Runtime>;
}

Пока это проходит проверку, но не тест. Конфигурация теста для трейта такая:

use palletB::{PutInStorage, Trait as PalletBTrait};

impl Trait for Test {
    type Event = ();
    type ExternalStorage = PutInStorage;
}

и это не работает с:

 type ExternalRulesStorage = PutInStorage;
                                         ^^^^^^^^^^^^ help: use `dyn`: `dyn PutInStorage`

 impl Trait for Test 
     ------------------- in this `impl` item
     type Event = ();
     type ExternalRulesStorage = PutInStorage;
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    
 type ExternalRulesStorage = PutInStorage;
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `pallet_rules::PutInStorage` cannot be made into an object

Я попробовал все предложения, которые дает мне компилятор Rust, но безуспешно. Прежде чем кто-то спросит, зачем мне это нужно в моем тесте, это связано с тем, что диспетчерский fn в decl_module! проверках указывает, существует ли определенная запись до того, как начнет обрабатывать и сохранять свои собственные записи. Это зависит от записи.


person woss    schedule 24.06.2020    source источник


Ответы (1)


Чтобы компилятор был доволен, ваша тестовая конфигурация также должна иметь экземпляр PalletB или что-то еще, что реализует PutInStorage.

Подобно тому, что вы уже делали в ./runtime/lib.rs:

impl Trait for Test {
    type Event = ();
    type ExternalStorage =  palletB::Module<Test>;
}

Обратите внимание, что теперь struct Test играет роль Runtime. Думаю, это единственное, чего вам не хватает.


При этом, похоже, вы идете по ложному пути в общем дизайне.

PalletA уже зависит от PalletB. Учитывая, что у вас также есть свойство связывать два PutInStorage, это плохой дизайн. Как правило, вы должны стараться и всегда выбирать одно из следующего:

  1. Два поддона будут зависеть друг от друга. В этом случае черты вам не нужны. Если одному нужно поместить что-то в хранилище другого, вы просто делаете это напрямую. В вашем примере я предполагаю, что PalletB имеет элемент памяти с именем pub Foo: u32 в decl_storage и PutInStorage записывает в него. В этом случае особенность не нужна. С PalletA можно просто сказать: palletB::Foo::put(value).

Обратите внимание, что этот подход следует выбирать с осторожностью, иначе вы можете получить много поддонов, зависящих друг от друга, что не очень хорошо.

  1. Вы решаете, что ваши поддоны НЕ зависят друг от друга, и в этом случае вы используете такую ​​черту, как PutInStorage. Кажется, что ваш код соответствует этому подходу, за исключением того, что вы определяете свойство PalletA как pub trait Trait: system::Trait. Здесь нет необходимости полагаться на PalletB, и, конечно же, вы можете стереть его и с Cargo.toml.
person kianenigma    schedule 24.06.2020
comment
Спасибо за ответ. Мне нужен типаж PalletB в трейте PalletA, если я хочу использовать хранилище для получения результатов, но НЕ, если я просто хочу использовать трейт PalletB для сохранения записи. Верно? - person woss; 24.06.2020
comment
И для чтения, и для записи вам действительно не нужно импортировать другую черту. Поместите общую черту GetterAdapter, у которой есть fn get() -> u32 и fn put(x: u32) в общее место. Один из поддонов будет использовать его как type Foo: GetterAdapter (позже вы просто вызовете T::GetterAdapter::set(...)), а другой будет его реализовывать. - person kianenigma; 25.06.2020