如何在 Substrate 中实现后台线程?

How to implement background thread in Substrate?

假设我想设计一个类似于众筹或拍卖的系统。这样的事件有一个固定的时间段是运行。我可以启动一个后台线程,该线程将定期检查是否已达到事件的结束时间并随后关闭该事件吗?我正在研究 futures crate(和其他一些),但它在 Substrate 中可用吗?有没有关于如何处理这种情况的最佳实践?

我认为 futures 的答案是否定的。这里有更多解释:

我认为最好考虑在 Substrate 运行时中可以使用哪些编程原语,而不是尝试使用通用编程中的概念(future ) 并尝试将其重新用于 Substrate 运行时(自上而下与自下而上的观点)。

那么,让我们考虑一下运行时的生命周期,看看有什么意义:

在运行时中,您有点被困在一个盒子里。每当要导入(或编写,但我们假设现在只导入)新块时,(始终是本机的)客户端会生成并执行(wasm)运行时代码,然后 killed 并放在一边(至少从运行时的角度来看——客户端有运行时缓存)。我的意思是,在每个块的执行结束时,您未提交状态(即写入存储)的任何内容都将丢失。这包括所有局部变量、堆栈、堆和其他任何东西。因此,即使您要使用未来来生成任务,这也并不真正适合 Substrate 运行时的编程模型,因为即使未来存在于运行时中,一旦块完成,wasm 实例就是死了,未来也是。

这一切都忽略了这样一个事实,即您只能在运行时使用支持 no_std 的 crate,因此并非每个异步库都可用。


正如我所暗示的,主要的解决方案可能是使用状态存储来记录拍卖的起点,这样在 x 个区块之后你仍然可以知道你是什么时候开始的,如果超过了某个阈值,然后你就可以完成你的拍卖了。您可以在拍卖期间使用时间戳或多个区块。大致如下:


trait Config: frame_system::Config {
    // duration in time or block number
    type AuctionDuration<T::BlockNumber>;
}

// inside your on_initialize
fn on_initialize(n: T::BlockNumber) {
    if n % T::AuctionDuration::get() == 0 {
        // ^^^^^ note: ensure this is non-zero, else panic in runtime might happen. 
        // time to close the auction.
    }
}