[Substrate Recipes翻译]1.21 Tightly- and Loosely-Coupled Pallets

Tightly- 和 Loosely-Coupled Pallets

check-membership crate包含了两个pallet去用稍微不同的方式去解决同一个问题。两个pallet都实现了一个单独的只能由访问控制列表(以下简称为ACL)里的caller成员执行的可调度函数。维护ACL的工作被抽象包装为另一个pallet,这个pallet和membership-managing pallet可以以两种方式来耦合,下面我们用tight和loose这两个变体pallet来演示这两种耦合方式。

孪生Pallets

在观察pallet代码之前,我们先来讲讲在pallets/check-membership目录下crate中的结构。这个目录文件夹是用来独立存放两个pallet的crate。这两个pallet被分别存放在pallets/check-membership/tightpallets/check-membership/loose目录下。在这个crate的主要文件lib.rs,我们简单地引入了各个变体pallet。

pub mod loose;
pub mod tight;

这一步骤让我们能够演示这两种耦合技术,同时把相关联的工程放在同一个crate。

控制访问

虽然使用这些孪生pallet主要目的是用来学习它们如何在membership-managing pallets中耦合,但是它们也体现了一个ACL的概念,这是我们先要关注学习的。

我们经常把一些函数指定为已授权的(permissioned),因此,这些函数只能被一个已被定义授权的用户组执行。在这个pallet,我们检查函数的caller是否符合已授权集合的成员。

loosely变体看上去像是这样:

/// 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.
/// 翻译:检查这个caller是不是通过MembershipSource type所提供的账户身份集合的其中一个成员。如果是的话发送事件,否则就报错。
fn check_membership(origin) -> DispatchResult {
    let caller = ensure_signed(origin)?;

    // Get the members from the vec-set pallet
    // 翻译:从vec-set pallet中得到成员组
    let members = T::MembershipSource::accounts();

    // Check whether the caller is a member
    // 翻译:检查caller是不是一个成员
    ensure!(members.contains(&caller), Error::<T>::NotAMember);

    // If the previous call didn't error, then the caller is a member, so emit the event
    // 翻译:如果先前的呼叫(call)没有发生错误,那么这个caller是个成员,因此发送事件
    Self::deposit_event(RawEvent::IsAMember(caller));
    Ok(())
}

耦合Pallets

事实上,每个check-membership pallet都包含了非常少的逻辑,它并不存储自己的数据,而由一个单独的外在(extrinsic)来检查会员数据。所有繁重的工作都被抽象包装为pallet。存在着两种不同的让一个pallet与另一个pallet耦合的方式,下面的部分将会研究这两种方式。

紧耦合(Tight Coupling)

紧耦合比松耦合更容易。当你为了把一些其他pallet作为依赖来进行紧耦合而去写pallet的时候,你明确指定你所要依赖的pallet的名字来作为你正在编写的pallet的配置trait所绑定的trait。现在将展示在紧耦合下的变体check-membership

pub trait Config: frame_system::Config + vec_set::Trait {
    // --snip--
}

这个pallet以及所有的pallet都与frame_system紧耦合

提供这个trait绑定意味着check-membership的紧耦合只可以安装在runtime中,而runtime中也安装着vec-set pallet。我们也可以在pallet的Cargo.toml文件中发现紧耦合,其中指定了vec-sec的名称。

vec-set = { path = '../vec-set', default-features = false }

为了真正得到集合下的成员,我们需要定义getter函数这样一种途径。

// Get the members from the vec-set pallet
// 翻译:从vec-set pallet中得到成员组
let members = vec_set::Module::<T>::members();

虽然紧耦合pallets在概念上很简单,但是它存在着缺点,即它由一个特定的实现而不是一个抽象接口来决定。这使得随着时间的推移,代码变得更难以维护,这是我们所不能接受的。check-membership的紧耦合版本完全由vec-set pallet来决定而不是由例如管理一系列账户等行为来决定。

松耦合(Loose Coupling)

松耦合解决了耦合特定实现的问题。当向其他pallet松耦合时,你需要在pallet的配置trait增加一个关联类型,并且确保你所提供的类型通过指定了一个trait绑定而实现了必要的行为。

pub trait Config: frame_system::Config {
    // --snip--

    /// A type that will supply a set of members to check access control against
    /// 翻译:一个能够提供一组成员来再次检查访问控制的类型
    type MembershipSource: AccountSet<AccountId = Self::AccountId>;
}

整个生态中的许多pallet都通过Currency trait而耦合在一起

拥有了这个关联类型意味着变体check-membership pallet的松耦合可以安装在任何runtime,这个变体可以提供一组账户去当作ACL来使用。AccountSet trait的代码存放在traits/account-set/src/lib.rs目录下,而且非常短。

pub trait AccountSet {
    type AccountId;

    fn accounts() -> BTreeSet<Self::AccountId>;
}

我们也可以看到松耦合在pallet的Cargo.toml文件下,其中还列出了account-set

account-set = { path = '../../traits/account-set', default-features = false }

为了真正得到一组成员,我们需要调用trait提供的accounts方法。

// Get the members from the vec-set pallet
// 翻译:从vec-set pallet中得到成员组
let members = T::MembershipSource::accounts();
上一篇:C++代码破解曹瞒走华容道(广搜、状态压缩、二叉排序树)


下一篇:2021-10-082020级国庆七天乐第4天 D