8

I have seen the Substrate Tutorial on creating crates of individual Substrate Runtime modules here in order to re-use the functionality, but I wondered if there is a way for one custom module to access the storage or functions from another custom module?

Something along these lines:

/// In ModuleA

    pub type IndexType = u64;

    decl_storage! {
        trait Store for Module<T: Trait> as ModuleA {
                pub MyIndexCount get(my_index_count): Option<IndexType>;
        }
    }

And then inside ModuleB - what do I need to do to use/include the functionality of ModuleA, and how do I call it?

/// In ModuleB

    decl_module! {
    pub struct Module<T: Trait> for enum Call where origin: T::Origin {
        fn deposit_event<T>() = default;

        pub fn edit_index(origin) -> Result {
            let sender = ensure_signed(origin)?;

            // --->>>> I want to read some storage from ModuleA whilst inside ModuleB
            let c: IndexType = ReadStorageFromModuleA >>> my_index_count().ok_or("Storage Read Error: cannot get index")?;

            // change storage in ModuleA from ModuleB
            WriteToStorageInModuleA <MyIndexCount<T>>::put(&c + 1);

            Ok(())
            }
        }
    }    
T9b
  • 3,312
  • 5
  • 31
  • 50
  • This is related to: https://stackoverflow.com/questions/56599293/what-is-the-purpose-of-pub-in-decl-storage – Shawn Tabrizi Jul 10 '19 at 13:44
  • You tagged your question with `substrate`, would you be interested in a dedicated Stack Exchange Q&A site for Substrate, Polkadot, et al. -- check out the [Area51 Substrate Proposal](https://area51.stackexchange.com/proposals/122626/substrate?referrer=NTUwMTkxYjJjOTJiNjE0YzMxYjgwMGNkZmFlYzdhZTczYjk1ZWY3ZGI4NzJmODUwN2RlYTQ2MTNjZTdkOTZhMAzuL-zybtPN9CHzwE-WUdvBC8WxvPG46b4ayadke6kG0) – q9f Jul 28 '19 at 11:00
  • @T9b Can you please check out and support the Substrate StackExchange proposal: https://area51.stackexchange.com/proposals/126136 – Shawn Tabrizi Dec 16 '21 at 13:02

1 Answers1

10

If you are building a module (module2) which has a direct dependency on another module (module1), you must inherit module1's trait in module2's trait definition:

pub trait Trait: module1::Trait {
    ...
}

To access public storage items from module1 in module2, you need to do the following:

  • Import the appropriate storage trait to access the storage API: StorageValue, StorageMap, etc...
  • Access the public storage through module1's storage type
    • <module1::Something<T>>::get()
    • <module1::Something<T>>::put()
    • etc...

To access other public functions from module 1 in module 2, you need to use the Module type:

<module1::Module<T>>::public_function();

Here is a simple example of two modules interacting in this way:

module1.rs

Note that all the things in this module are marked public (pub)

use support::{decl_module, decl_storage, StorageValue};

pub trait Trait: system::Trait {}

decl_storage! {
    trait Store for Module<T: Trait> as TemplateModule {
        pub Something: u32;
    }
}

decl_module! {
    pub struct Module<T: Trait> for enum Call where origin: T::Origin {
    }
}

impl<T: Trait> Module<T> {
    pub fn get_value() -> u32 {
        <Something<T>>::get()
    }
}

module2.rs

use support::{decl_module, decl_event, StorageValue, dispatch::Result};
use system::ensure_signed;

use crate::module1;

pub trait Trait: module1::Trait {
    type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
}

decl_module! {
    /// The module declaration.
    pub struct Module<T: Trait> for enum Call where origin: T::Origin {
        fn deposit_event<T>() = default;

        pub fn get_value_directly(origin) -> Result {
            let who = ensure_signed(origin)?;
            let value = <module1::Something<T>>::get();
            Self::deposit_event(RawEvent::ValueIs(value, who));
            Ok(())
        }

        pub fn set_value_directly(origin, value: u32) -> Result {
            let _ = ensure_signed(origin)?;
            <module1::Something<T>>::put(value);
            Ok(())
        }

        pub fn get_value_public_function(origin) -> Result {
            let who = ensure_signed(origin)?;
            let value = <module1::Module<T>>::get_value();
            Self::deposit_event(RawEvent::ValueIs(value, who));
            Ok(())
        }
    }
}

decl_event!(
    pub enum Event<T> where <T as system::Trait>::AccountId {
        ValueIs(u32, AccountId),
    }
);
Shawn Tabrizi
  • 12,206
  • 1
  • 38
  • 69
  • So if I understand correctly, there are two possibilities to interact with storage from another module, 1) wrapping in a public function in the original module, and then calling the function and 2) calling directly, provided the storage was also declared as public. Of these two is there a recommended pattern or are both equally acceptable? – T9b Jul 10 '19 at 20:52
  • 1
    I think exposing public functions is definitely the way to go. In general, I would not want to expose that many public storage items since that let's other modules mess with your storage directly, and in ways you may not want. Public functions act as an API to external logic to safely access and modify your storage. – Shawn Tabrizi Jul 10 '19 at 21:54
  • @ShawnTabrizi I am not sure why, I am trying to use exactly same method as you suggested but how does this relate with using pallet? – Afeez Aziz Feb 09 '21 at 03:56
  • I'm sorry but I don't understand what you are asking here. Do you want to open a new question? – Shawn Tabrizi Feb 09 '21 at 09:05
  • this shows how to couple pallets using [tight coupling](https://github.com/substrate-developer-hub/recipes/blob/master/text/pallet-coupling.md#tight-coupling), but an improvement would be to instead use [loose coupling](https://github.com/substrate-developer-hub/recipes/blob/master/text/pallet-coupling.md#loose-coupling) – Luke Schoen Mar 01 '21 at 08:06