github: https://github.com/soonlabs/igloo.git

igloo\example\src\main.rs

async fn main() -> Result<()> {
    env_logger::init();

    let (instant_sender, instant_receiver) = channel(1024);
    let instanct_driver = InstantDeriveImpl::new(instant_receiver);

    let (da_sender, da_receiver) = channel(1);
    let da_driver = DaDeriveImpl::default();

    let (attribute_sender, attribute_receiver) = channel(1024);
    let mut runner = SimpleRunner::new(Path::new("/tmp/igloo-example"), attribute_sender)?; // blockstore和accountsdb 存储路径

    runner.register_instant(instanct_driver); // 从instant_sender获取非安全区块数据
    runner.register_da(da_driver.clone()); // 从DA获取安全区块数据

    MockLayer1::new(1000, instant_sender).run(); // 从起始高度 1000,每隔12s 产生一个mock区块,喂到 instant_sender
    TxServer::new(runner.get_engine().stream().clone()).run();// 每秒随机0-4个L2交易,喂到stream
    Batcher::new(da_sender).run(attribute_receiver); // 将da_sender接收到的交易通过receive_tx_loop放到cache,每隔20s将catche中的交易通过da_sender发送给da_receiver
    da_driver.run(da_receiver); // 将da_receiver接收到的数据,写入到cached,模拟DA

    loop {
        if let Err(e) = runner.advance().await {
            // We should match the error type and panic accordingly in production code
            error!("Error: {}", e);
        }

        tokio::time::sleep(std::time::Duration::from_secs(2)).await;
    }
}

igloo\example\src\runner.rs

impl SimpleRunner {
    pub fn new(
        base_path: &Path,
        attribute_sender: Sender<PayloadAttributeImpl>,
    ) -> anyhow::Result<Self> {
        Ok(Self {
            engine: SvmEngine::new(base_path, attribute_sender)?,
            instant_derive: None,
            da_derive: None,
            current_head: None,
            sequence_number: 0,
        })
    }

    async fn advance_unsafe(&mut self) -> Result<()> {
        let info = self.instant_derive()?.get_new_block().await?; // 从L1获取L2提交的交易
async fn advance_safe(&mut self) -> Result<()> { // 从DA中检查并获取未执行的区块数据,DA中的数据认为是已经经过检查,所以作为安全数据
        trace!("begin of da derive");
        while let Some(attribute) = self.da_derive()?.next().await {
            if self.has_executed(&attribute) { // 检查是否已经执行过
                debug!(
                    "skip executed attribute at L1 height {} sequence number {}",
                    attribute.epoch.block_height(),
                    attribute.sequence_number
                );
                continue;
            }

            let block = self.engine.produce_block(attribute).await?;
            self.new_block(block).await?;
        }
        trace!("end of da derive");
        Ok(())
    }

igloo\example\src\l2\engine.rs

pub async fn produce_block(
        &mut self,
        attribute: PayloadAttributeImpl,
    ) -> anyhow::Result<BlockPayloadImpl> {
        let mut transactions = (*attribute.transactions).clone();
        let extra_txs = {
            self.stream
                .write()
                .await
                .next_batch(Default::default())
                .await
        };
        trace!(
            "produce block with {} deposit txs, {} normal txs",
            transactions.len(),
            extra_txs.len()
        );
        transactions.extend(extra_txs);

        let new_attribute = PayloadAttributeImpl { // 组装区块所需数据
            transactions: Arc::new(transactions),
            epoch: attribute.epoch,
            sequence_number: attribute.sequence_number,
        };
        let block = self.producer.produce(new_attribute.clone()).await?;

        if let Err(e) = self.attribute_sender.send(new_attribute).await {
            error!("Failed to send attribute: {}", e);
        }

        Ok(block)
    }
}

总结

该Demo只演示了基础的模拟区块组装,数据与DA层Mock流转,核心层代码逻辑并未开源,关注后期更新