Search code examples
substrate

In Substrate is there a way to use storage and functions from one custom module in another?


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(())
            }
        }
    }    

Solution

  • 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),
        }
    );