simplified for single sequencer

This commit is contained in:
kashepavadan 2026-06-24 11:12:36 -04:00
parent ce09c5ba0e
commit 6f4da18a55
2 changed files with 8 additions and 48 deletions

View File

@ -1,35 +1,27 @@
use lb_core::mantle::ops::channel::MsgId;
use lb_zone_sdk::sequencer::InscriptionInfo; use lb_zone_sdk::sequencer::InscriptionInfo;
use crate::message::Msg; use crate::message::Msg;
/// Trait for the TUI's view of zone state. /// Trait for the sequencer/indexer's view of zone state.
/// ///
/// The TUI feeds SDK events into this trait; the trait owns persistence. /// The sequencer/indexer feeds SDK events into this trait; the trait owns persistence.
/// `InMemoryZoneState` is the demo implementation. A real sequencer would /// `InMemoryZoneState` is the demo implementation. A real sequencer would
/// implement it over a DB so `published`/`adopted`/`finalized` survive /// implement it over a DB so `published`/`finalized` survive
/// restarts (the SDK's own checkpoint covers tx-level resume separately). /// restarts (the SDK's own checkpoint covers tx-level resume separately).
/// ///
/// Three lists, each ordered by arrival: /// Three lists, each ordered by arrival:
/// - `published`: our submissions, in submit order, until they finalize or get /// - `published`: our submissions, in submit order, until they finalize or get
/// orphaned. /// orphaned.
/// - `adopted`: others' inscriptions on canonical, deduped by `msg_id` (reorgs
/// can re-adopt the same one), in first-sighting order.
/// - `finalized`: all inscriptions below LIB, in canonical order — the SDK /// - `finalized`: all inscriptions below LIB, in canonical order — the SDK
/// delivers `TxsFinalized`/`FinalizedInscriptions` per block. /// delivers `TxsFinalized`/`FinalizedInscriptions` per block.
/// ///
/// Replay-idempotent: `on_adopted` and `on_finalized` dedup by `msg_id`, so /// Replay-idempotent: `on_finalized` dedup by `msg_id`, so
/// resuming from a persisted state and re-receiving backfill is harmless. /// resuming from a persisted state and re-receiving backfill is harmless.
pub trait ZoneState: Send { pub trait ZoneState: Send {
fn on_published(&mut self, info: &InscriptionInfo); fn on_published(&mut self, info: &InscriptionInfo);
fn on_adopted(&mut self, adopted: &[InscriptionInfo]);
/// Remove our orphaned entry from `published`. Caller is expected to
/// auto-republish via `handle.publish_message`.
fn on_orphaned(&mut self, msg_id: &MsgId);
fn on_finalized(&mut self, inscriptions: &[InscriptionInfo]); fn on_finalized(&mut self, inscriptions: &[InscriptionInfo]);
fn published(&self) -> &[Msg]; fn published(&self) -> &[Msg];
fn adopted(&self) -> &[Msg];
fn finalized(&self) -> &[Msg]; fn finalized(&self) -> &[Msg];
} }
@ -37,7 +29,6 @@ pub trait ZoneState: Send {
#[derive(Default)] #[derive(Default)]
pub struct InMemoryZoneState { pub struct InMemoryZoneState {
published: Vec<Msg>, published: Vec<Msg>,
adopted: Vec<Msg>,
finalized: Vec<Msg>, finalized: Vec<Msg>,
} }
@ -47,21 +38,6 @@ impl ZoneState for InMemoryZoneState {
.push(Msg::from_payload(info.this_msg, &info.payload)); .push(Msg::from_payload(info.this_msg, &info.payload));
} }
fn on_adopted(&mut self, adopted: &[InscriptionInfo]) {
for info in adopted {
if !self.adopted.iter().any(|m| m.msg_id == info.this_msg) {
self.adopted
.push(Msg::from_payload(info.this_msg, &info.payload));
}
}
}
fn on_orphaned(&mut self, msg_id: &MsgId) {
if let Some(i) = self.published.iter().position(|m| &m.msg_id == msg_id) {
self.published.remove(i);
}
}
fn on_finalized(&mut self, inscriptions: &[InscriptionInfo]) { fn on_finalized(&mut self, inscriptions: &[InscriptionInfo]) {
for info in inscriptions { for info in inscriptions {
if let Some(i) = self if let Some(i) = self
@ -70,8 +46,6 @@ impl ZoneState for InMemoryZoneState {
.position(|m| m.msg_id == info.this_msg) .position(|m| m.msg_id == info.this_msg)
{ {
self.published.remove(i); self.published.remove(i);
} else if let Some(i) = self.adopted.iter().position(|m| m.msg_id == info.this_msg) {
self.adopted.remove(i);
} }
if !self.finalized.iter().any(|m| m.msg_id == info.this_msg) { if !self.finalized.iter().any(|m| m.msg_id == info.this_msg) {
self.finalized self.finalized
@ -84,10 +58,6 @@ impl ZoneState for InMemoryZoneState {
&self.published &self.published
} }
fn adopted(&self) -> &[Msg] {
&self.adopted
}
fn finalized(&self) -> &[Msg] { fn finalized(&self) -> &[Msg] {
&self.finalized &self.finalized
} }

View File

@ -14,7 +14,7 @@ use lb_core::mantle::ops::channel::{ChannelId, inscribe::Inscription};
use lb_key_management_system_service::keys::{ED25519_SECRET_KEY_SIZE, Ed25519Key}; use lb_key_management_system_service::keys::{ED25519_SECRET_KEY_SIZE, Ed25519Key};
use logos_blockchain_zone_sdk::{ use logos_blockchain_zone_sdk::{
adapter::NodeHttpClient, adapter::NodeHttpClient,
sequencer::{Event, FinalizedOp, OrphanedTx, SequencerCheckpoint, SequencerClient, ZoneSequencer}, sequencer::{Event, FinalizedOp, SequencerCheckpoint, SequencerClient, ZoneSequencer},
}; };
use reqwest::Url; use reqwest::Url;
use thiserror::Error; use thiserror::Error;
@ -124,7 +124,7 @@ impl Sequencer {
tokio::spawn(async move { tokio::spawn(async move {
// Wait until the sequencer completes cold-start backfill before publishing. // Wait until the sequencer completes cold-start backfill before publishing.
let mut ready_rx = batch_client.subscribe_ready(); let mut ready_rx = batch_client.subscribe_ready();
let _ = ready_rx.wait_for(|r| *r).await; drop(ready_rx.wait_for(|r| *r).await);
let mut interval = tokio::time::interval(Duration::from_millis(100)); let mut interval = tokio::time::interval(Duration::from_millis(100));
loop { loop {
@ -137,14 +137,13 @@ impl Sequencer {
loop { loop {
let event = sequencer.next_event().await; let event = sequencer.next_event().await;
handle_event(event, &mut sequencer, &mut state, &checkpoint_path); handle_event(event, &mut state, &checkpoint_path);
} }
} }
} }
fn handle_event( fn handle_event(
event: Event, event: Event,
sequencer: &mut ZoneSequencer<NodeHttpClient>,
state: &mut InMemoryZoneState, state: &mut InMemoryZoneState,
checkpoint_path: &str, checkpoint_path: &str,
) { ) {
@ -152,16 +151,7 @@ fn handle_event(
Event::Ready => { Event::Ready => {
info!("Sequencer ready"); info!("Sequencer ready");
} }
Event::BlocksProcessed { checkpoint, channel_update, finalized } => { Event::BlocksProcessed { checkpoint, channel_update: _, finalized } => {
state.on_adopted(&channel_update.adopted);
for orphan in &channel_update.orphaned {
let OrphanedTx::Inscription(info) = orphan else { continue };
state.on_orphaned(&info.this_msg);
debug!(msg_id = %hex::encode(info.this_msg.as_ref()), "Auto-republishing orphan");
if let Err(e) = sequencer.handle().publish(info.payload.clone()) {
error!("failed to auto-republish: {e}");
}
}
let inscriptions: Vec<_> = finalized let inscriptions: Vec<_> = finalized
.into_iter() .into_iter()
.flat_map(|tx| tx.ops.into_iter()) .flat_map(|tx| tx.ops.into_iter())