diff --git a/BEPs/BEP-684.md b/BEPs/BEP-684.md new file mode 100644 index 00000000..e6653ac7 --- /dev/null +++ b/BEPs/BEP-684.md @@ -0,0 +1,341 @@ +
+ BEP: 684 + Title: Header-Only Voting for Fast Finality + Status: Draft + Type: Standards + Created: 2026-04-23 + Description: Decouple consensus voting from block execution by allowing validators to vote upon header verification, removing execution from the critical voting path. ++ +# BEP-684: Header-Only Voting for Fast Finality + +- [BEP-684: Header-Only Voting for Fast Finality](#bep-684-header-only-voting-for-fast-finality) + - [1. Summary](#1-summary) + - [2. Abstract](#2-abstract) + - [3. Motivation](#3-motivation) + - [4. Specification](#4-specification) + - [4.1 Header-Only Voting Protocol](#41-header-only-voting-protocol) + - [4.2 Header Verification](#42-header-verification) + - [4.3 Import-Gated Finality](#43-import-gated-finality) + - [4.4 Lazy Execution Pipeline](#44-lazy-execution-pipeline) + - [4.5 Invalid Block Recovery](#45-invalid-block-recovery) + - [5. Safety Analysis](#5-safety-analysis) + - [5.1 Theorem 1 — Accountable Safety](#51-theorem-1--accountable-safety) + - [5.2 Theorem 2 — No Premature Finality](#52-theorem-2--no-premature-finality) + - [5.3 Theorem 3 — Fast Node Safety Under Invalid Successor](#53-theorem-3--fast-node-safety-under-invalid-successor) + - [5.4 Theorem 4 — Fork Consistency](#54-theorem-4--fork-consistency) + - [6. Liveness Analysis](#6-liveness-analysis) + - [6.1 Theorem 5 — Normal Liveness](#61-theorem-5--normal-liveness) + - [6.2 Theorem 6 — Invalid Block Liveness Bound](#62-theorem-6--invalid-block-liveness-bound) + - [6.3 Degradation Hierarchy](#63-degradation-hierarchy) + - [7. Related Work](#7-related-work) + - [8. Backward Compatibility](#8-backward-compatibility) + - [9. Security Considerations](#9-security-considerations) + - [10. License](#10-license) + +## 1. Summary + +This BEP allows validators to cast Fast Finality votes upon verifying the block header alone, without waiting for full block import (execution), removing execution time from the critical voting path. + +## 2. Abstract + +Under the current Fast Finality mechanism ([BEP-126](./BEP126.md)), a validator must fully import a block — including transaction execution and state root verification — before voting. This places execution time on the critical path of vote propagation, imposing a hard lower bound on block interval: + +``` +BlockInterval > 2 × OWD + T_import +``` + +This BEP decouples voting from execution: validators verify only the block header (parent hash, height, proposer, signature, timestamp) and vote immediately. Full block import proceeds asynchronously, and finality is still gated on successful import. This removes `T_import` from the critical voting path, relaxing the constraint to: + +``` +BlockInterval > 2 × OWD + T_header_verify +``` + +where `T_header_verify ≈ 2ms` versus `T_import ≈ 100–300ms`, significantly lowering the minimum achievable block interval while maintaining the safety and liveness guarantees of BEP-126. + +**Key assumption**: BSC has no light clients — all participants are full nodes that eventually execute every block. + +## 3. Motivation + +The current voting pipeline requires execution in the critical path: + +``` +|<------------ BlockInterval ------------>| +| δ_net | T_import | δ_net | δ_agg |idle| +| 75ms | 100-300ms| 75ms | 10ms | | + + B_h arrives → execute → vote → votes arrive at P_{h+1} +``` + +Execution (`T_import`) consumes the majority of the time budget. As block intervals decrease, execution becomes the dominant bottleneck — the constant `2 × OWD` overhead plus `T_import` leaves diminishing room for further reduction. + +With Header-Only Voting, execution is removed from the critical path: + +``` +|<------------ BlockInterval ------------>| +| δ_net | δ_hdr| δ_net | δ_agg | | +| 75ms | 2ms | 75ms | 10ms | | + + header arrives → verify → vote → votes arrive at P_{h+1} + ↓ (async) + import B_h in background +``` + +The critical path shrinks from `2 × OWD + T_import ≈ 312ms` to `2 × OWD + T_header ≈ 152ms`, unlocking further block interval reductions that are infeasible under the current protocol. + +## 4. Specification + +### 4.1 Header-Only Voting Protocol + +The BEP-126 vote rules (Rule 1: no double voting at same height; Rule 2: no surround voting; Rule 3: vote for canonical chain tip) remain unchanged. The only change is the **vote trigger condition**: + +``` +Current (BEP-126): vote for B_h iff imported[h] == B_h +Header-Only Voting: vote for B_h iff header_verified[h] == B_h +``` + +Where `header_verified[h]` means the header of `B_h` has passed the checks defined in §4.2. + +### 4.2 Header Verification + +A validator may vote for block `B_h` after verifying the following header fields: + +| Check | Description | +|-------|-------------| +| Parent link | `header.parent_hash == canonical_tip_hash()` | +| Height | `header.height == canonical_tip_height() + 1` | +| Proposer | `header.proposer ∈ {in_turn(h), backup(h)}` | +| Signature | `verify_signature(header, header.proposer) == true` | +| Timestamp | `parent.timestamp < header.timestamp ≤ now() + CLOCK_DRIFT` | + +The following fields are **not** verified before voting (deferred to import): +- `state_root`, `tx_root`, `receipt_root` +- Transaction validity, gas usage, execution results + +### 4.3 Import-Gated Finality + +Voting is decoupled from execution, but **finality is not**. The BEP-126 finalization rule (two consecutive justified blocks → the first is finalized) applies only after both blocks have been successfully imported: + +``` +finalized(B_h) iff: + justified(B_h) ∧ justified(B_{h+1}) ∧ imported(B_h) ∧ imported(B_{h+1}) +``` + +This guarantees that no block is finalized without its execution result being verified by all honest validators. + +### 4.4 Lazy Execution Pipeline + +With voting decoupled from execution, blocks are imported asynchronously. Define execution debt `D(h)` as the number of blocks that have been voted on but not yet imported at height `h`: + +``` +D(h) = h - max{h' : imported(B_{h'}) == true} +``` + +Stability requires `E[T_import] < BlockInterval`, so execution debt remains bounded in expectation. When debt accumulates due to heavy blocks, the pipeline absorbs transient spikes: + +``` +EXECUTION_DEBT_MAX = 2 # maximum pipeline depth +``` + +If `D(h) > EXECUTION_DEBT_MAX`, the validator pauses voting until execution catches up. + +### 4.5 Invalid Block Recovery + +A Byzantine proposer may produce a block `B_h*` with a valid header but invalid body (e.g., incorrect state root). Under Header-Only Voting, honest validators will vote for `B_h*` based on the header, but import will fail. + +**Invalid Block Skip Rule**: if a full node fails to import `B_h` within `IMPORT_TIMEOUT` (= 3 × BlockInterval): + +1. Mark height `h` as execution-invalid. +2. Do not finalize any block through `B_h`. +3. Continue processing consensus at subsequent heights. +4. When a valid block at height `h' > h` forms a new justified chain, resume finalization. + +Stall bound: a single Byzantine proposer causes at most one stalled height. With 6/21 Byzantine validators, the probability of ≥3 consecutive Byzantine proposers is `(6/21)³ ≈ 2.3%`. Single stall duration ≤ `IMPORT_TIMEOUT + BlockInterval ≈ 4 × BlockInterval`. + +## 5. Safety Analysis + +### 5.1 Theorem 1 — Accountable Safety + +If two conflicting blocks `B_h` and `B_h'` are both finalized, then ≥ ⅓ of validators violated BEP-126 vote rules. + +``` +Proof: + Finality requires justified(B) ∧ imported(B). + Header-Only Voting changes when votes are cast, not the vote rules themselves. + BEP-126 Rule 1 (no double vote) and Rule 2 (no surround vote) still hold. + The safety proof of BEP-126 Theorem 1 applies without modification. ∎ +``` + +### 5.2 Theorem 2 — No Premature Finality + +No block is finalized without successful import by all honest validators. + +``` +Proof: + By §4.3, finalized(B_h) requires imported(B_h). + Imported(B_h) means the full block has been executed and the state root verified. + A block with an invalid body will fail import → never satisfy finalized(). + Therefore, finality implies execution correctness. ∎ +``` + +### 5.3 Theorem 3 — Fast Node Safety Under Invalid Successor + +It is safe for a fast node to finalize `B_h` when both `B_h` and `B_{h+1}` are justified, even if `B_{h+1}`'s body is invalid. + +Combined with [BEP-648](./BEP-648.md) (in-memory vote pool finality), a fast node can determine finality without waiting for attestations to appear in block headers. The full finality path becomes: + +``` +BEP-648: justified(B) when ≥14 votes observed in vote pool (no header inclusion needed) +BEP-684: votes cast upon header verification (no import needed) +Combined: fast node finalizes B_3 when vote pool shows ≥14 votes for both B_3 and B_4 + — before B_4 is included in any header, and before B_4 is imported. +``` + +``` +Scenario: + B_3: valid header, valid body → justified (≥14 votes in pool, per BEP-648) + B_4: valid header, INVALID body → justified (≥14 header votes in pool, per BEP-648) + + Full node: imported(B_3)=true, imported(B_4)=false → finalized(B_3)=false + Fast node: does not verify state_root → considers both "imported" + → finalized(B_3)=true (earliest, via BEP-648 vote pool) + +Question: Is the fast node's finalization of B_3 correct? + +Proof — Safety (no conflicting finality): + Finalizing B_3 means: no conflicting B_3' at height 3 can also be finalized. + This guarantee depends solely on BEP-126 vote rules: + Rule 1: no validator votes for two different blocks at the same height. + Rule 2: no surround voting. + These rules are unchanged by HOV or BEP-648 — votes are still per-height. + → A conflicting B_3' requires ≥7 validators violating Rule 1. + → Safety holds regardless of B_4's body validity. ✓ + +Proof — Correctness (B_3 has been execution-verified by supermajority): + B_4 receiving ≥14 votes means ≥14 validators accepted B_4's header. + B_4.parent_hash = hash(B_3), so these validators have B_3 in their canonical chain. + Under the current protocol (pre-HOV): voting requires import, so ≥14 validators + have already fully imported and executed B_3 — its state root is verified by + a supermajority. + Under HOV: voting only requires header verification, but the lazy execution + pipeline imports blocks asynchronously. With EXECUTION_DEBT_MAX = 2, + B_3 is imported before or shortly after B_4 arrives. Even in the worst case, + the ≥14 validators will eventually import B_3 and detect any invalidity. + In both cases: ≥14 honest validators have (or will have) verified B_3's execution. + B_3's state = f(state(B_2), txs(B_3)) — independent of B_4's body. + Since B_3 is valid, the fast node's state at B_3 is correct. ✓ + +Proof — Consistency (fast node does not diverge from full nodes): + Full nodes do not finalize B_3 via the B_3→B_4 path (imported(B_4) fails). + But B_3 IS on the canonical chain — honest full nodes successfully import B_3. + The chain will eventually recover from B_4's invalidity (§4.5): + An honest proposer produces B_4' or B_5 on a valid fork. + B_3 gets finalized through a later justified pair. + → Fast node and full nodes converge on the same finalized B_3. ✓ + +Conclusion: + The fast node finalizes B_3 earlier than full nodes (because it doesn't + gate on imported(B_4)), but this is safe because: + 1. B_3 itself is valid — verified by ≥14 validators who voted for B_4. + 2. No conflicting B_3' can be finalized (vote rule guarantee). + 3. Full nodes will eventually finalize the same B_3 through recovery. + BEP-648 accelerates when the fast node observes justification (vote pool + vs header inclusion), but does not change what justification means. + The fast node's existing trust model (trust consensus, skip execution) + is preserved — neither HOV nor BEP-648 weakens it. ∎ +``` + +### 5.4 Theorem 4 — Fork Consistency + +Header-Only Voting does not introduce new fork scenarios beyond BEP-126. + +``` +Proof: + A fork requires two justified blocks at the same height. + Justification requires ≥ 14/21 votes. + BEP-126 Rule 1 prevents any validator from voting for two blocks at the same height. + This rule is unchanged — votes are still per-height, only the trigger changes. + → Fork requires ≥ 7 validators violating Rule 1, same as BEP-126. ∎ +``` + +## 6. Liveness Analysis + +### 6.1 Theorem 5 — Normal Liveness + +After GST, if the proposer at height `h` is honest, `B_h` is finalized within `2 × BlockInterval + T_import`. + +``` +Proof: + t=0: P_h broadcasts valid B_h + t ≤ δ_net: honest validators receive header → cast header vote + t ≤ 2×δ_net: P_{h+1} receives ≥15 votes → constructs B_{h+1} + t ≤ 2×δ_net: honest validators receive body(B_h) → begin import + t ≤ BlockInterval: B_{h+1} broadcast + t ≤ BlockInterval + δ_net: honest validators receive header(B_{h+1}) → vote + t ≤ 2×BlockInterval: both B_h and B_{h+1} justified + t ≤ 2×BlockInterval + T_import: both imported + + Finality ≤ 2 × BlockInterval + T_import ∎ +``` + +### 6.2 Theorem 6 — Invalid Block Liveness Bound + +A Byzantine proposer producing an invalid block delays finality by at most `O(BlockInterval)`, and does not permanently stall the chain. + +``` +Proof: + After B_h* fails import: + Invalid Block Skip Rule triggers within IMPORT_TIMEOUT = 3 × BlockInterval. + Next honest proposer builds on B_{h-1}. + Validators who have not voted at height h can vote for the replacement. + Stall ≤ IMPORT_TIMEOUT + BlockInterval ≈ 4 × BlockInterval. + With 15/21 honest validators, next proposer is honest with probability 71%. ∎ +``` + +### 6.3 Degradation Hierarchy + +| Level | Condition | Finality Latency | +|-------|-----------|-----------------| +| BEP-126 + HOV | ≥14 header votes + import OK | ~2 × BlockInterval + T_import | +| Parlia fallback | ≥11/21 online | Probabilistic finality | + +## 7. Related Work + +| | Ethereum | Solana (Alpenglow) | BSC (this BEP) | +|---|---|---|---| +| Execution timing | Synchronous | Synchronous (lazy planned) | Asynchronous (lazy) | +| Vote prerequisite | Full attestation | Block received | Header only | +| Finality prerequisite | Epoch boundary | 1–2 rounds | Import confirmed | +| Invalid block handling | Slashing | Slashing | Existing bad block mechanism | +| Light client | Yes | Yes | No (all full nodes) | + +**vs Ethereum ePBS**: ePBS separates builder from proposer, requiring fraud/validity proofs for dishonest builders. BSC Header-Only Voting separates voting from execution — invalid bodies are caught by the existing bad block mechanism, no new proof system needed. + +**vs Solana Lazy Execution**: Solana plans to reach consensus on transaction ordering only, with state commitment deferred to later blocks. BSC Header-Only Voting is more conservative — the proposer still commits to `state_root` in the header, and finality still requires import verification. + +## 8. Backward Compatibility + +This BEP is **not backward compatible**. It changes the vote trigger condition from full import to header verification, requiring a hard fork with coordinated client upgrades across all validators and full nodes. + +Dependencies: +- [BEP-126](./BEP126.md): Fast Finality Mechanism (base protocol) +- [BEP-590](./BEP-590.md): Extended Voting Rules (vote aggregation flexibility) +- [BEP-648](./BEP-648.md): Enhanced Fast Finality via In-Memory Voting Pool (vote pool finality) + +## 9. Security Considerations + +| Threat | Impact | Mitigation | +|--------|--------|-----------| +| Byzantine proposer: invalid body | Single-height stall | Existing bad block mechanism + Invalid Block Skip Rule (§4.5) | +| Byzantine proposer: missing body | Votes cast but import impossible | Import timeout → skip | +| Network partition after header vote | Finality stall | Resumes after partition heals | +| Execution slower than block rate | Execution debt growth | Gas limit tuning + `EXECUTION_DEBT_MAX` backpressure | + +Core invariants: +1. **Vote-Finality gap**: header votes may exist without finality. Finality always requires import. +2. **No light client leakage**: no component acts on header-vote finality alone. +3. **Bad block handling unchanged**: detection and existing mechanisms are preserved; no new slashing conditions. + +## 10. License + +The content is licensed under [CC0](https://creativecommons.org/publicdomain/zero/1.0/).