为什么使用 <T::Lookup 作为 StaticLookup>::Source 而不是普通的 T::AccountId?

问题描述

根据此 PR,所有可调度调用都应使用 <T::Lookup as StaticLookup>::Source 而不是 T::AccountId。为什么通过查找处理转移而不是用他们的帐户解决用户问题更好? Substrate 中的查找是如何工作的,是否有替代 StaticLookup方法

最后,除了 IdentityLookup 之外还有其他类型吗?您将如何使用它们?

type Lookup = IdentityLookup<AccountId>;

解决方法

StaticLookup 是一个地址的抽象,它可以将多种不同的地址类型转换为一个底层的 AccountId。

想象一个只使用 AccountId 的外部变量。与该函数交互的唯一方法是为链上帐户提供原始 AccountId。

相反,使用 StaticLookup,您可以提供任何兼容的地址格式,并且会有额外的逻辑用于将该地址转换为基础帐户。

想象一下:

enum Address {
    AccountId([u8; 32]),// 32 byte account id
    String(Vec<u8>),// arbitrary string
}

这是一个实际示例,说明您将如何允许人们在您的链上使用名称服务。例如你可以这样做:

transfer(b"shawntabrizi",100 UNIT)

除了:

transfer(5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,100 UNIT)

StaticLookup 将包含任何适当的代码,用于将已知格式转换为您需要的最终 AccountId。

想象一下下面的代码:

struct NameServiceLookup;
impl StaticLookup for NameServiceLookup {
    type Source = Address;
    type Target = AccountId;

    fn lookup(a: Address) -> Result<AccountId,LookupError> {
        match a {
            Address::AccountId(id) => Ok(id),Address::String(string) => {
                string_to_account_id(string).ok_or(LookupError)
            },}
    }

    fn unlookup(a: [u8; 32]) -> Address {
        Address::AccountId(a)
    }
}

在这里您可以看到我们有特殊的逻辑来处理地址,如果它是 AccountId 或 String。这就是 StaticLookup 最终会提供的。

IdentityLookup 的实现是一个简单的传递,它准确地返回输出的输入。因此,当您没有任何这种花哨的逻辑,并且希望直接使所有 StaticLookupAccountId 完全相同时,这将是您想要使用的:

pub struct IdentityLookup<T>(PhantomData<T>);
impl<T: Codec + Clone + PartialEq + Debug> StaticLookup for IdentityLookup<T> {
    type Source = T;
    type Target = T;
    fn lookup(x: T) -> Result<T,LookupError> { Ok(x) }
    fn unlookup(x: T) -> T { x }
}