+ ~ - + - + - + - ~ ~ *
| commonware
* ~ + + - ~ - + - * - +

Minimmit: Fast Finality with Even Faster Blocks

June 24, 2025

Over the last few months, there has been renewed interest in developing propose-and-vote consensus protocols that reach finality after just one round of voting (~100-200ms). "Two-Phase" protocols, not without tradeoff, only remain safe if a Byzantine adversary controls less than ~20% of stake (rather than the ~33% tolerance typically considered). Concerned primarily with addressing this drop in fault tolerance, recent constructions propose augmenting Byzantine fault tolerance with crash fault tolerance to retain some path to finality under a "blended" ~33% assumption. Minimmit, a new propose-and-vote construction below, optimizes for a different goal: minimizing block time.

Phase Comparison
Figure 1: Two-Phase protocols commit after just one round of voting.

Background

In March, Matter Labs released ChonkyBFT: Consensus Protocol of ZKsync. In May, Offchain Labs released Kudzu: Fast and Simple High-Throughput BFT and Anza Labs released Alpenglow at Solana Accelerate. And just a few days ago, Supra Research and Espresso Systems released Hydrangea: A Fast and Simple Consensus Protocol for High-Throughput Blockchains.

All capable of propose-and-vote confirmation in ~100-200ms, this cohort of new constructions primarily differs in the technique employed to finalize blocks if faults exceed ~20% of stake (when comprised of at most f Byzantine faults and p crash faults). Finalizing quickly via some "fast path" when replicas are honest and online, these constructions fallback to a "slow path" that resembles the "Three-Phase" protocols commonly deployed today.

Alpenglow Fallback
Figure 2: Alpenglow supports a "slow-finalization" path (source).

Minimmit: Fast Finality with Even Faster Blocks

Today, we are excited to share a different take on propose-and-vote consensus: Minimmit: Fast Finality with Even Faster Blocks. Like the constructions above, Minimmit delivers minimal confirmation latency under the ~20% Byzantine fault assumption. Unlike those constructions, however, it optimizes for view latency instead of f+ confirmation robustness. In an alto-like configuration (with 50 uniformly distributed validators), we expect a Minimmit-powered blockchain to reach 130ms block time and 250ms finality. In a regionally-biased configuration, we expect Minimmit to deliver 50ms block time and 100ms finality.

Faster Blocks
Figure 3: On a real network, messages can arrive at very different times and advancing to the next view after observing a 40% quorum can be much faster than observing an 80% quorum.

While not yet peer-reviewed or fully implemented, we are releasing Minimmit under both an MIT and Apache-2 license for others to build with and build upon. Below, we provide a high-level summary of the specification and share some intuition about its correctness:

1. Introduction

Minimmit is a responsive, leader-based consensus protocol designed for simplicity and speed, tolerant of a Byzantine adversary that controls fewer than 20% of replicas. Minimmit advances to the next view when a 40% quorum is reached and finalizes blocks when an 80% quorum is reached (after only a single round of voting). Minimmit can be instantiated with a number of practical optimizations to improve performance when deployed in production.

2. Model & Parameters

3. Quorums

There exists ≥ 1 honest replica in any Q-set and L-set intersection.

4. Message Types

Message Purpose
genesis The genesis block.
propose(c, v, (c', v')) Leader's proposal c for view v with parent c' in view v'.
notarize(c, v) Vote to finalize block c in view v.
nullify(v) Vote to advance to view v + 1.
notarization(c, v) Certificate of ≥ L notarize(c, v) messages for (c, v).
nullification(v) Certificate of ≥ L nullify(v) messages for view v.
proof(v) Either a notarization(*, v) or a nullification(v) certificate.

5. Initial Replica State

view         = 0
notarized    = ⊥         # the proposal this replica has notarized
nullified    = false     # whether this replica has nullified this view
timer        = None      # time until nullify if not yet nullified or notarized
messages     = []        # list of messages this replica has seen
proofs       = []        # list of proofs this replica has collected

6. External Functions

// Select the leader for view `v`
fn leader(v) -> L;

// Build a block on top of `c'`. This should pass `verify(c, c')`.
fn build(c') -> c;

// Verify whether `c` is valid given the parent `c'`. Anything produced by
// `build(c')` should pass `verify(c, c')`.
fn verify(c, c') -> bool;

7. Helpers

// Find a valid parent to build on
fn select_parent(v) -> (c', v') {
    let i = v - 1;
    while i >= 0 {
        if notarization(c', i) ∈ proofs[i] {
            // If there are multiple, pick any.
            return (c', i);
        }
        if nullification(i) ∈ proofs[i] {
            i -= 1;
            continue;
        }
        return ⊥;
    }
    return genesis;
}

// Ensure there are proofs for all views between `v` and `v'`
fn valid_parent(v, (c', v')) -> bool {
    let i = v - 1;
    while i > v' {
        if nullification(i) ∈ proofs[i] {
            i -= 1;
            continue;
        }
        return false;
    }
    return notarization(c', v') ∈ proofs[v']
}

// Enter view `next`
fn enter_view(next) {
    if view >= next {
        return;
    }
    view = next;
    notarized = ⊥;
    nullified = false;
    timer = 2Δ;
}

// Record a message from a `replica`
fn record_message(replica, message) -> bool {
    if replica ∉ messages[message.view] {
        messages[message.view][replica] = [];
    }
    if message ∉ messages[message.view][replica] {
        messages[message.view][replica].add(message);
        return true;
    }
    return false;
}

// Prune data less than `view`
fn prune(view) {
    messages.remove(m => m.view < view);
    proofs.remove(p => p.view < view);
}

8. Protocol for View v

8.1. Propose

If the leader, propose.

  1. Upon entering view v, if identity is equal to leader(v):
    1. (c', v') = select_parent(v) (if , return).
    2. c = build(c').
    3. notarized = c.
    4. Broadcast propose(c, v, (c', v')).

Treat propose(c, v, (c', v')) as a leader l's notarize(c, v).

8.2. Notarize

Upon receipt of a first valid block proposal from leader, broadcast notarize(c, v).

  1. On receiving first propose(c, v, (c', v')) from leader(v):
    1. If notarized != ⊥ or nullified, return.
    2. If !valid_parent(v, (c', v')), return.
    3. If !verify(c, c'), return.
    4. notarized = c.
    5. Broadcast notarize(c, v).

8.3. Nullify by Timeout

If timer expires, broadcast nullify(v) if not yet broadcasted notarize(c, v).

  1. On timer expiry:
    1. If notarized != ⊥ or nullified, return.
    2. nullified = true.
    3. Broadcast nullify(v).

8.4. Notarization & Finalization

After L messages, create and broadcast a notarization(c, v) certificate. After Q messages, finalize.

  1. On receiving notarize(c, v) from replica r:
    1. If !record_message(r, notarize(c, v)), return.
  2. On observing ≥ L notarize(c, v) messages:
    1. Assemble notarization(c, v).
    2. Add notarization(c, v) to proofs.
    3. Broadcast notarization(c, v).
    4. enter_view(v + 1).
  3. On observing ≥ Q notarize(c, v) messages:
    1. Finalize c and all of its ancestors.
    2. prune(v).

8.5. Nullification

After L messages, create and broadcast a nullification(v) certificate.

  1. On receiving nullify(v) from replica r:
    1. If !record_message(r, nullify(v)), return.
  2. On observing ≥ L nullify(v) messages (or a single nullification(v) message):
    1. Assemble nullification(v).
    2. Add nullification(v) to proofs.
    3. Broadcast nullification(v).
    4. enter_view(v + 1).

8.6 Nullify by Contradiction

If you have already broadcast notarize(c, v) for a c that cannot be finalized directly, broadcast nullify(v) to ensure some proof(v) will exist in view v.

  1. On observing messages from ≥ L replicas of either nullify(v) or notarize(*, v) (where notarized != ⊥ and notarized != *):
    1. nullified = true.
    2. Broadcast nullify(v).

9. Intuition

9.1 General

9.2 Safety

9.3 Liveness

10. Extensions

Minimmit can be instantiated in several different ways to tune performance when deployed to production. Some examples are below:

Have an idea to simplify, improve, or extend Minimmit? Open a PR or reach out at minimmit@commonware.xyz.