erhant 8d09ffd733 feat(sequencer): two-tier chain state and multi-sequencer support
Decentralized-sequencing foundation: a shared chain_state crate (two-tier
head/final ChainState, apply_block, AcceptOutcome, StallReason, and the
absorbed channel-consistency machinery), turn-gated block production, the
publisher follow path for adopted/orphaned/finalized peer blocks, and
persistence that keeps disk order equal to apply order under the chain lock.

Rebased onto dev after #600/#606: chain_consistency is absorbed into
chain_state, the sequencer bootstrap's verify_and_reconstruct is re-wired
onto the two-tier ChainState (reconstruction applies channel history
through the final tier and persists via the follow-path primitives), and
test fixtures adopt the SequencerSetup builder extended with
with_bedrock_signing_key.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 11:43:57 +03:00

51 lines
1.8 KiB
Rust

use common::{HashType, block::BlockHeader};
use logos_blockchain_zone_sdk::Slot;
use serde::{Deserialize, Serialize};
use crate::ingest_error::BlockIngestError;
/// Diagnostic record of the first block that broke the L2 chain.
///
/// The block-derived fields are `None` for a deserialize break (no header was
/// ever parsed). `l1_slot` is the L1 slot the breaking inscription was read at.
/// `first_seen` is the breaking block's L2 timestamp (`None` for a deserialize break).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StallReason {
pub block_id: Option<u64>,
pub block_hash: Option<HashType>,
pub prev_block_hash: Option<HashType>,
pub l1_slot: Slot,
pub error: BlockIngestError,
pub first_seen: Option<u64>,
/// Number of later non-chaining blocks (orphans, since the tip is frozen).
///
/// TODO: We could store a different "branch" of blocks following this break, but for now we
/// just count them.
pub orphans_since: u64,
}
impl StallReason {
/// First stall for a break, built from the breaking block's header
/// (`None` for a deserialize break).
#[must_use]
pub fn new(header: Option<&BlockHeader>, l1_slot: Slot, error: BlockIngestError) -> Self {
Self {
block_id: header.map(|header| header.block_id),
block_hash: header.map(|header| header.hash),
prev_block_hash: header.map(|header| header.prev_block_hash),
first_seen: header.map(|header| header.timestamp),
l1_slot,
error,
orphans_since: 0,
}
}
/// A later stall on the same break: bumps `orphans_since`, preserving the
/// original cause.
#[must_use]
pub const fn escalate(mut self) -> Self {
self.orphans_since = self.orphans_since.saturating_add(1);
self
}
}