Sequencer Decentralization and Force Inclusion TODO
Concept
Most rollups have a single entity operating the sequencer that orders transactions. This gives fast confirmation and low latency, but it leaves a censorship/liveness risk: if that entity excludes or halts a particular user's transactions, the user simply can't use the chain. Force inclusion sets a floor under that risk — if a user submits a transaction directly to an inbox contract on L1, bypassing the sequencer, the rollup must include it after a fixed delay window for the resulting state transition to be considered valid at all. That guarantees users at least an escape hatch, such as withdrawal, even if the sequencer censors them. Sequencer decentralization goes further, spreading the ordering authority itself across multiple parties — shared sequencers, stake-weighted rotation, or having the L1 proposer set order directly are all approaches being tried, each with different tradeoffs in latency, MEV, and complexity.
The worst-case scenario for any service deployed on an L2 is the sequencer halting or excluding just your transactions — and whether a force-inclusion path exists, and how long its delay window is, determines how long funds stay stuck when that happens. That's a practical criterion for choosing which chain to deploy on.
Code & Formula
# 시퀀서 분산화와 강제 포함(force inclusion) — 시퀀서가 검열해도 L1 inbox를 거치면 지연 창 이후 반드시 포함된다.
# 시퀀서가 특정 발신자를 계속 배제해도, 지연 창(DELAY)이 지난 forced tx는 다음 블록에 강제로 실린다.
DELAY = 3 # 강제 포함까지 걸리는 블록 수
class Sequencer:
def __init__(self, censored_sender):
self.censored_sender = censored_sender
self.included = []
def build_block(self, block_num, mempool, forced_inbox):
already = {id(tx) for tx in self.included}
# 강제 포함 마감이 지난 tx는 검열 여부와 무관하게 반드시 포함해야 유효한 블록이다
due = [tx for tx in forced_inbox if block_num - tx["submitted_at"] >= DELAY and id(tx) not in already]
censorable = [tx for tx in mempool if tx["sender"] != self.censored_sender and id(tx) not in already]
block = due + [tx for tx in censorable if id(tx) not in {id(t) for t in due}]
self.included.extend(block)
return block
alice_tx = {"sender": "alice", "tx": "swap", "submitted_at": 0}
mempool = [alice_tx]
forced_inbox = [alice_tx] # alice가 시퀀서 mempool과 L1 inbox에 동시 제출
seq = Sequencer(censored_sender="alice")
for block_num in range(6):
block = seq.build_block(block_num, mempool, forced_inbox)
status = [tx["sender"] for tx in block] if block else "(empty, 시퀀서가 검열 중)"
print(f"블록 {block_num}: 포함된 tx = {status}")
if block:
break
print(f"\n시퀀서가 alice를 계속 배제했지만, 지연 창({DELAY}블록) 이후 강제 포함으로 결국 실렸다:", bool(seq.included))
docs/code/algorithms/algorithms-64.py
Exercise
Find the force-inclusion (or forced-withdrawal) entry-point contract and its delay window in your L2's docs, then submit a forced-inclusion transaction through L1 yourself on testnet.
Practical Connection
Verex's market settlement isn't final until the oracle result is confirmed and the redeem transaction lands on-chain, so whether a force-inclusion path exists to push settlement/withdrawal through even under sequencer censorship is part of the protocol's safety story.
Where it lands in Jayverse
- Devnet: pick and document the force-inclusion window before it's needed. When Devnet moves from Anvil-on-Sepolia to a real OP-Stack L2, the force-inclusion delay window becomes a concrete parameter Verex settlement depends on, not a detail to leave for later.
- Verex: test the redeem path through forced inclusion, not just document it. Submit a forced-inclusion transaction on testnet for the oracle-result redeem flow specifically, since that path is where a censored sequencer would strand user funds.
- Auditor: add the censorship-window as a checked field. Record the force-inclusion delay for any market whose settlement depends on L2 inclusion, alongside the resolution methodology it already tracks.
Key expressions
| Expression | 뜻 · 쓰이는 자리 |
|---|---|
| escape hatch | 최후의 탈출구, 비상 안전장치 · "guarantees users at least an escape hatch" |
| set a floor under | ~의 하한선을 정해 최소한을 보장하다 · "Force inclusion sets a floor under that risk" |
| bypass | 우회하다, 건너뛰다 · "bypassing the sequencer" |
| censorship/liveness risk | 특정 거래가 배제되거나 멈춰버릴 위험 · "a censorship/liveness risk" |
| halt | 작동을 멈추다, 정지시키다 · "if that entity excludes or halts" |
| stuck | 묶여서 움직이지 못하는 · "how long funds stay stuck when that happens" |
| stake-weighted rotation | 지분 비중에 따라 순번을 돌리는 방식 · "stake-weighted rotation" |
| MEV | 최대 추출 가능 가치(Maximal Extractable Value) · 시퀀서 분산화 방식들 간의 트레이드오프로 언급된다. "different tradeoffs in latency, MEV, and complexity" |
If you study this on a given day, add a note link and a ✅ to this line in the source curriculum (docs/knowledge/dev-100-curriculum.md) and this spot will lead straight to the note body. You can also write directly on this page — but regenerating overwrites it, so it's safer to keep anything you want to save as markdown under docs/algorithms/.