简体   繁体   中英

How to use PalletB to save record from PalletA without PalletA knowing anything about internals of the saving in substrate and rust

I'd like to save a record from PalletA in PalletB by simply passing the raw data and waiting for the return.

I have tried following:

// ./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);
    }
}

then in

// ./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;
}

then I added the definition to the runtime like this:

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

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

So far this passes the check but not the test. The test configuration for the trait is like this:

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

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

and this fails with the:

 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

I tried all the suggestions the Rust compiler gives me but without any luck. Before someone asks why do I need this in my test, it's because a dispatchable fn in decl_module! checks does a certain record exists before starts processing and saving its own records. It is dependent on record to exist.

To make the compiler happy, your test config must also have an instance of PalletB, or anything else that implements PutInStorage .

Similar to what you've done already in ./runtime/lib.rs :

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

Note that now struct Test is the one playing the role of Runtime . I think this is the only thing that you are missing.


That being said, you seem to be on the wrong track in the overall design.

PalletA already depends on PalletB . Given that you also have a trait to link the two PutInStorage , this is not a good design. Generally, you should try and always chose one of the following:

  1. Two pallets will depend on one another. In this case you don't need traits. If one needs to put something to the storage of the other one, you just do it directly . In your example, I assume that PalletB has a storage item called pub Foo: u32 in decl_storage and PutInStorage writes to this. If this is the case, there's no need for a trait. From PalletA you can just say: palletB::Foo::put(value) .

Note that this approach should be chosen with care, otherwise you might end up with a lot of pallets depending on one another which is not good.

  1. You decide that your pallets do NOT depend on one another, in which case you use some trait like PutInStorage . Your code seem to be aligned with this approach, except you define PalletA's Trait as pub trait Trait: system::Trait . There's no need to depend on PalletB here, and of course you can wipe it from Cargo.toml as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM