如何将一个托盘中的存储变量用作另一个托盘中的配置变量?

How can I use a storage variable in one pallet as a configuration variable in another?

所以你有 2 个托盘。目标是在 pallet_1:

中有一个配置变量 C

pallet_1 的 trait 中的配置变量应该类似于 MyConfig: Get<u32>

像这样:https://github.com/paritytech/substrate/blob/master/frame/recovery/src/lib.rs#L200

所以这表示我们需要定义一个实现 Get<T> 特征的类型:

https://github.com/paritytech/substrate/blob/master/frame/support/src/traits.rs#L471

所以这只是一个函数fn get() -> T

然后假设您有 pallet_2,其中有一些您想要控制此配置的存储项目:

decl_storage!{
    MyStorage: u32;
}

在您的 runtime/src/lib.rs 中,您定义如下内容:

struct StorageToConfig;
impl Get<u32> for StorageToConfig {
     fn get() -> u32 {
         return pallet_2::MyStorage::get();
    }
}

如何在 pallet_1 中的特征定义中使用此结构,并确保运行时自动推送(或 pallet_1 从运行时拉取)MyStorage var in pallet_2?

这实际上是创建一个 trait impl 结构,然后在运行时将结构传递给接收者(通过使用 trait),我学习这个的方法是查看所有已经存在的 pallets那里看看pass信息如何

例如作者的这个特征 https://github.com/paritytech/substrate/blob/640dd1a0a44b6f28af1189f0293ab272ebc9d2eb/frame/authorship/src/lib.rs#L39

在这里实现 https://github.com/paritytech/substrate/blob/77819ad119f23a68b7478f3ac88e6c93a1677fc1/frame/aura/src/lib.rs#L148

这里是合成的(不是光环实现而是会话)

https://github.com/paritytech/substrate/blob/549050b7f1740c90855e777daf3f9700750ad7ff/bin/node/runtime/src/lib.rs#L363

你也应该阅读这篇文章https://doc.rust-lang.org/book/ch10-02-traits.html#:~:text=A%20trait%20tells%20the%20Rust,type%20that%20has%20certain%20behavior

这是一个工作示例,说明如何将配置特征的值附加到另一个托盘的存储项目。

托盘 1

这里是pallet_1,里面有我们要使用的存储项目。

NOTE: This storage is marked pub so it is accessible outside the pallet.

use frame_support::{decl_module, decl_storage};
use frame_system::ensure_signed;

pub trait Trait: frame_system::Trait {}

decl_storage! {
    trait Store for Module<T: Trait> as TemplateModule {
        pub MyStorage: u32;
    }
}

decl_module! {
    pub struct Module<T: Trait> for enum Call where origin: T::Origin {
        #[weight = 0]
        pub fn set_storage(origin, value: u32) {
            let _ = ensure_signed(origin)?;
            MyStorage::put(value);
        }
    }
}

托盘 2

这里是 pallet_2,它有一个配置特征,我们要用 pallet_1 中的存储项填充:

use frame_support::{decl_module, dispatch, traits::Get};
use frame_system::ensure_signed;

pub trait Trait: frame_system::Trait {
    type MyConfig: Get<u32>;
}

decl_module! {
    pub struct Module<T: Trait> for enum Call where origin: T::Origin {
        #[weight = 0]
        pub fn do_something(origin) -> dispatch::DispatchResult {
            let _ = ensure_signed(origin)?;

            let _my_config =  T::MyConfig::get();

            Ok(())
        }
    }
}

运行时配置

这两个托盘非常简单,可以分开工作。但是如果我们想连接它们,我们需要配置我们的运行时:

use frame_support::traits::Get;

impl pallet_1::Trait for Runtime {}

pub struct StorageToConfig;
impl Get<u32> for StorageToConfig {
     fn get() -> u32 {
         return pallet_1::MyStorage::get();
    }
}

impl pallet_2::Trait for Runtime {
    type MyConfig = StorageToConfig;
}

// We also update the `construct_runtime!`, but that is omitted for this example.

这里我们定义了一个结构 StorageToConfig,它实现了 pallet_2 所期望的 Get<u32> 特征。此结构告诉运行时何时调用 MyConfig::get(),然后它应该调用 pallet_1::MyStorage::get(),后者读取运行时存储并获取该值。

所以现在,在 pallet_2 中对 T::MyConfig::get() 的每次调用都将是一次存储读取,并且将获得在 pallet_1 中设置的任何值。

如果有帮助请告诉我!