From 7405d813b23196dfd8d2c9fca20d0f1061ae7535 Mon Sep 17 00:00:00 2001 From: Chihyun Song Date: Thu, 30 Apr 2026 11:02:32 +0900 Subject: [PATCH] kip-227: update byzantine filtering formula --- KIPs/kip-227.md | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/KIPs/kip-227.md b/KIPs/kip-227.md index 7cad8e0..8e510f0 100644 --- a/KIPs/kip-227.md +++ b/KIPs/kip-227.md @@ -37,14 +37,14 @@ The framework promotes consistent uptime and reliability. Validators have an inc ### Parameters -| Constant | Value/Definition | -| :-------------------------- | :---------------------------------------------------------------------- | -| `FORK_BLOCK` | TBD | -| `CANDIDATE_MSG_TIMEOUT` | Protocol parameter (milliseconds). Default = 500ms. | -| `EPOCH_LENGTH` | 86,400 blocks (approximately 1 day, assuming 1-second block time) | -| `MAX_BYZANTINE_NODES` (`F`) | Calculated as `F = (n - 1) // 3`, where `n` is the number of validators | -| `PFS_THRESHOLD` | 2 (max proposal failures per epoch) | -| `CFS_THRESHOLD` | 300 (max candidate failures per epoch) | +| Constant | Value/Definition | +| :-------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `FORK_BLOCK` | TBD | +| `CANDIDATE_MSG_TIMEOUT` | Protocol parameter (milliseconds). Default = 500ms. | +| `EPOCH_LENGTH` | 86,400 blocks (approximately 1 day, assuming 1-second block time) | +| `MAX_BYZANTINE_NODES` (`F`) | Calculated as `F = floor(len(proposerSet) / 3)`, where `proposerSet` is the set of distinct proposers observed in the current epoch up to and including the block at which CFS is computed | +| `PFS_THRESHOLD` | 2 (max proposal failures per epoch) | +| `CFS_THRESHOLD` | 300 (max candidate failures per epoch) | ### Data Structures and Protocol Primitives @@ -158,7 +158,8 @@ Each score is per epoch, computed from `pfReport` and `cfReport` in epoch blocks Format: `pfs(N) -> map[proposerAddr]score` **Candidate Failure Score (CFS)**: For a given block number `N`, CFS MUST be computed from `cfReport(b)` for blocks `b ∈ [epochStart(N), N]` (note that `cfReport(epochStart(N))` is empty). -For each candidate `C` and reporter (proposer of block `N`): if `C` is in `cfReport(N)`, that counts as 1 failure. +For each candidate `C` and reporter (proposer of block `b`): if `C` is in `cfReport(b)`, that counts as 1 failure. +Let `proposerSet` be the set of distinct proposers across all blocks `b ∈ [epochStart(N), N]` (every block contributes its proposer to `proposerSet`, including blocks with an empty `cfReport`), and let `F = floor(len(proposerSet) / 3)`. For each candidate, sum failures per reporter over the epoch, discard the highest `F` reporter totals (Byzantine filtering), and sum the remainder to obtain CFS. Format: `cfs(N) -> map[candidateAddr]score` @@ -169,15 +170,16 @@ _Example 1: Short epoch_ ``` epoch = 5 -len(validator) = 4 len(candidates) = 3 -F = 1 proposer(5)=P1, cfReport(5)=[] proposer(6)=P2, cfReport(6)=[] proposer(7)=P3, cfReport(7)=[C1,C2,C3] proposer(8)=P4, cfReport(8)=[C1,C2] proposer(9)=P4, cfReport(9)=[C1,C2] + +proposerSet = {P1, P2, P3, P4} +F = len(proposerSet) / 3 = 4 / 3 = 1 ``` Aggregated `cfReport(N)` where N ∈ \[5, 9\]: