Lifecycle — Block Stage Transitions
Subscribe
{"subscribe": ["Lifecycle"]}
Message Format
{
"seq": 46,
"Lifecycle": {
"block_hash": "0xabc123...",
"block_number": 56147820,
"from_stage": "Proposed",
"to_stage": "Voted",
"time_in_previous_stage_ms": 412.5,
"block_age_ms": 412.5,
"txn_count": 150,
"gas_used": null
}
}
Fields
| Field | Type | Description |
|---|---|---|
block_hash | string | Consensus block ID (0x-prefixed) |
block_number | u64 | Block number |
from_stage | string | null | Previous stage (null for initial Proposed) |
to_stage | string | New stage: Proposed, Voted, Finalized, Verified, Rejected |
time_in_previous_stage_ms | f64 | null | Time spent in previous stage (ms) |
block_age_ms | f64 | Total time since Proposed (ms) |
txn_count | usize | Number of transactions in the block |
gas_used | u64 | null | Gas used (available after BlockEnd) |
MonadBFT Stages
Proposed (~0 ms) → Voted (~400 ms) → Finalized (~800 ms) → Verified (terminal)
│
(any stage) ──────────────────────────► Rejected (terminal)
| Stage | Trigger Event | Latency | Guarantee |
|---|---|---|---|
| Proposed | BlockStart | ~0 ms | Speculative |
| Voted | BlockQC | ~400 ms | Speculative finality (2/3+ validators) |
| Finalized | BlockFinalized | ~800 ms | Full finality — irreversible |
| Verified | BlockVerified | After finalization | State root verified |
| Rejected | BlockReject | Varies | Block dropped |
Description
Lifecycle is a high-level metric tracking block transitions between consensus stages. Each transition emits one message.
Typical sequence for a block:
Lifecycle: Proposed(block_age_ms ≈ 0)Lifecycle: Voted(block_age_ms ≈ 400)Lifecycle: Finalized(block_age_ms ≈ 800)Lifecycle: Verified(block_age_ms ≈ 900+)
Usage Examples
Finality Monitoring
{"subscribe": ["Lifecycle"]}
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.lifecycle) {
const lc = msg.Lifecycle;
console.log(`Block ${lc.block_number}: ${lc.from_stage || "new"} → ${lc.to_stage} (${lc.block_age_ms.toFixed(0)} ms)`);
}
};
Pattern: Buffering + Finality Confirmation
For applications requiring finality (bridge, exchange):
const pendingBlocks = new Map(); // block_number → events[]
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.Events) {
for (const e of msg.Events) {
if (!pendingBlocks.has(e.block_number)) pendingBlocks.set(e.block_number, []);
pendingBlocks.get(e.block_number).push(e);
}
}
if (msg.lifecycle) {
const lc = msg.Lifecycle;
if (lc.to_stage === "Finalized") {
const events = pendingBlocks.get(lc.block_number);
if (events) {
processConfirmedEvents(events); // safe to process
pendingBlocks.delete(lc.block_number);
}
}
if (lc.to_stage === "Rejected") {
pendingBlocks.delete(lc.block_number); // discard
}
}
};
Metrics Dashboard
{"subscribe": ["TPS", "Lifecycle", "ContentionData"]}
3 items = within default subscription limit.
REST Equivalent
# All tracked blocks
curl http://localhost:8443/v1/blocks/lifecycle
# Specific block
curl http://localhost:8443/v1/blocks/56147820/lifecycle
Frequency
2-4 messages per block (one per stage transition). At 400 ms block time, ~5-10 messages per second.