[Substrate Recipes translation] 1.21 tight - and loose coupled pallets

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

Tags: Rust

Posted on Tue, 12 Oct 2021 00:27:35 -0400 by timon