Tightly - and loosly coupled pallets
Check membership crit contains two pallets to solve the same problem in slightly different ways. Both pallets implement a separate schedulable function that can only be executed by the caller member in the access control list (hereinafter referred to as ACL). ACL maintenance is abstractly packaged as another pallet. This pallet and membership managing pallet can be coupled in two ways. Next, we use the two variant pallets of tight and loose to demonstrate these two coupling methods.
Twin Pallets
Before we look at the pallet code, let's talk about the structure of crite in the pallets / check membership directory. This directory folder is used to store the crates of two pallets independently. The two pallets are stored in the pallets / check membership / tight and pallets / check membership / loose directories respectively. In the main file lib.rs of this crate, we simply introduced various variants of pallet.
pub mod loose; pub mod tight;
This step allows us to demonstrate the two coupling techniques while putting the associated projects in the same crate.
Control access
Although the main purpose of using these twin pallets is to learn how to couple them in membership managing pallets, they also embody the concept of ACL, which we should first focus on learning.
We often specify some functions as authorized. Therefore, these functions can only be executed by a defined authorized user group. In this pallet, we check whether the caller of the function matches the members of the authorized collection.
The loosly variant looks like this:
/// Checks whether the caller is a member of the set of Account Ids provided by the /// MembershipSource type. Emits an event if they are, and errors if not. ///Check whether this caller is one of the members of the account identity set provided by MembershipSource type. If yes, send the event, otherwise an error will be reported. fn check_membership(origin) -> DispatchResult { let caller = ensure_signed(origin)?; // Get the members from the vec-set pallet // Get member groups from VEC set pallet let members = T::MembershipSource::accounts(); // Check whether the caller is a member // Check whether the caller is a member ensure!(members.contains(&caller), Error::<T>::NotAMember); // If the previous call didn't error, then the caller is a member, so emit the event // If there is no error in the previous call, the caller is a member, so the event is sent Self::deposit_event(RawEvent::IsAMember(caller)); Ok(()) }
Coupled Pallets
In fact, each check membership pallet contains very little logic. It does not store its own data, but a separate external checks the member data. All heavy work is abstractly packaged as pallet. There are two different ways to couple one pallet with another, which will be studied in the following sections.
Tight Coupling
Tight coupling is easier than loose coupling. When you write a pallet to tightly couple some other pallets as dependencies, you explicitly specify the name of the pallet you want to rely on as the trail bound by the configuration trail of the pallet you are writing. The variant check membership under tight coupling will now be shown.
pub trait Config: frame_system::Config + vec_set::Trait { // --snip-- }
This pallet and all pallets are associated with the frame_system tight coupling
Providing this trait binding means that the tight coupling of check membership can only be installed in runtime, and VEC set pallet is also installed in runtime. We can also find tight coupling in pallet's Cargo.toml file, which specifies the name of VEC sec.
vec-set = { path = '../vec-set', default-features = false }
In order to really get the members under the collection, we need to define the getter function.
// Get the members from the vec-set pallet // Get member groups from VEC set pallet let members = vec_set::Module::<T>::members();
Although tightly coupled palets is conceptually simple, it has the disadvantage that it is determined by a specific implementation rather than an abstract interface. This makes the code more difficult to maintain over time, which is unacceptable. The tightly coupled version of check membership is completely determined by VEC set pallet, not by behaviors such as managing a series of accounts.
Loose Coupling
Loose coupling solves the problem of coupling specific implementations. When loosely coupled to other pallets, you need to add an association type to the pallet's configuration trail, and ensure that the type you provide implements the necessary behavior by specifying a trail binding.
pub trait Config: frame_system::Config { // --snip-- /// A type that will supply a set of members to check access control against ///A type that provides a set of members to check access control again type MembershipSource: AccountSet<AccountId = Self::AccountId>; }
Many pallet s in the whole ecosystem are coupled together through Currency trait
Having this association type means that the loose coupling of the variant check membership pallet can be installed at any runtime. This variant can provide a set of accounts to be used as ACL S. The code of AccountSet trait is stored in the traits / account set / SRC / lib.rs directory and is very short.
pub trait AccountSet { type AccountId; fn accounts() -> BTreeSet<Self::AccountId>; }
We can also see the loose coupling in pallet's Cargo.toml file, which also lists account set.
account-set = { path = '../../traits/account-set', default-features = false }
In order to really get a group of members, we need to call the accounts method provided by trait.
// Get the members from the vec-set pallet // Get member groups from VEC set pallet let members = T::MembershipSource::accounts();