Repository navigation
Conversation
Word the cfReport rules in terms of Report now that header.VRank also carries the parent round, so an empty cfReport no longer reads as an empty header field. An epoch start sets Report to CandTesting. Spell out the decoding rule (three items, canonical ParentRound) and the parent committee and its quorum. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since the permissionless fork a committed seal signs the block hash, the COMMIT code and the round byte, which the block hash leaves out. No KIP stated this, yet KIP-227 verifies ParentCommittedSeal against it. Define it in the committed-seals consensus rule and have KIP-227 refer to it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pfReport(N) now lists the failed proposers of block N-1, so Rule 2's trigger is a non-empty pfReport of the block, not a failure at the block, and a PFS demotion lands one block later than before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A zero-length VRank encoded as an explicit empty RLP string decodes to a present field and re-encodes as an extra trailing header element, so nodes that know the field and nodes that do not would disagree on the header. Clients therefore reject any present VRank before FORK_BLOCK, not only a non-empty one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A block prepared in an earlier round is re-proposed unchanged at later rounds, and only the round byte in header.Extra is rewritten, so the header keeps the seal of the proposer that built it. Requiring the author to equal GetProposer(N, round) rejects such a block on import. Clients check membership in qualified(N) instead, which is also what the pre-fork rule checked; the committed seals already bind the author through the block hash. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A proposer does not send VRankPreprepare for a view above MAX_ROUND, a candidate ignores such a solicitation, and MAX_ROUND is a protocol constant. A block committed above MAX_ROUND follows a stall of over half an hour, so skipping its evaluation is by design, and every round VRank carries is one byte, which leaves rounds above 255 out of scope. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Both VRank messages sign keccak256 over a VRANK_PREPREPARE_V1 or VRANK_CANDIDATE_V1 domain, an 8-byte big-endian chain id and block number, a one-byte round and the 32-byte block hash, with a 65-byte ECDSA and a 96-byte BLS signature. The candidate's BLS key is read from AddressBookV2 at the head after FORK_BLOCK and from KIP-113 before it, with the proof of possession checked at lookup, and VRank is the optional tail field after ExcessBlobGas. Without the byte layout, the key source and the field position, a second client cannot verify either signature or encode the header. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
CANDIDATE_MSG_TIMEOUT is a 500 ms protocol constant, and VRank messages go only to directly connected CN peers on kaia68 or later, where a full per-peer queue may drop them. A candidate answers each view at most once and only for a block that extends its head, the proposer evaluates the first stored reply per candidate and view, and a proposer that lost its timing data reports nothing, so cfReport can under-report but never over-report. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A cfReport covers its writer's own most recent prior proposal in the epoch, so a proposer's first block in the epoch reports nothing. The example now spans blocks 10 to 16 with four distinct proposers, every non-empty report follows an earlier proposal by the same proposer, and the aggregated table is unchanged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The reporter credited for cfReport(N) and counted in proposerSet is the author of block N, which a hash-locked re-proposal does not change. The target T is the author's most recent proposal in the epoch, meaning the block whose committing round it proposed, and an author reports on each of its proposals at most once. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A VRankPreprepare or VRankCandidate with an unknown or unauthorized sender, a bad ECDSA or BLS signature, a round outside [0, MAX_ROUND] or a mismatched block is discarded, and the receiver may disconnect the peer. Both nodes stay in CNPeers, so KIP-311 reconnection restores the link after one dial cycle, while a reply for a view the receiver did not propose is only ignored. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The stability list has carried the downtime requirement since the reputation design that preceded PFS and CFS, but nothing measures downtime: the only scores are proposal and candidate failures, and the violations list maps only PFS. Rather than drop the requirement, mark it as future work so readers do not expect a penalty v3.0.0 does not apply. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The pseudocode does not say which PFS Rule 2 reads. State that block N+1's transitions use pfs(N), that a violator held back by a full budget is judged again, and how this meets an epoch block, and pin the address order behind sorted_validators. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The transition table said PFS "exceeds" PFS_THRESHOLD, while the pseudocode, the rationale and KIP-227 all use PFS >= PFS_THRESHOLD. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eshold The transition table said the score "exceeds" CFS_THRESHOLD, while the parameter table and KIP-227 both use CFS >= CFS_THRESHOLD. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AddressBookV2's pause() and exit() from ValActive revert unless the ValActive count exceeds minActiveCount, the same floor the system transitions keep. The user-tx rows listed only the slot limit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The violation transition runs every block, epoch blocks included, so Rule 1 exits retained validators below MinStake in the same block, and the pseudocode comment claiming it skips epoch blocks was wrong. The slot limits now name epochVACount, defined as the ValActive count after the epoch pass and before the violation pass, instead of "the count at epoch start". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A second client needs the post-fork seal quorum as a number: ceil(2n/3) over the committee, all n seals when n < 4, a duplicated seal rejecting the block, and pre-fork blocks keeping 2f+1. The Committee row also claimed every member may cast header votes, which does not hold in single governance mode, the mode mainnet and Kairos run. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The committee of N includes the system transitions applied at the start of N, while the reward-eligible set and staking amounts come from the state after N-1. A validator moved by a system transition therefore joins or leaves the reward inputs one block after the committee, an accepted limitation that a second client must reproduce. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The ValActive row said a suspended validator earns no rewards, while
RewardEligible is {ValActive}; the reward rule holds and the row now
speaks of consensus only. Suspension is written down as an overlay that
leaves counts, guards and Rules 1-2 untouched, with the end of the
all-suspended fallback and the suspender's operating rule.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The KIP gave only durations, which leaves open when a deadline is set, whether parameter updates move it, and which block applies the expiry. It now fixes all three and names the user calls that must revert with TimeoutExpired, so no user transaction can pre-empt the system transition at the deadline. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The KIP ranked by "staking amount" without saying which amount: it is the node's CnStakingV4 staking() minus unstaking(), floored to whole KAIA and read from the parent state, with Consensus Liquidity stake left out. MinStake comes from the AddressBookV2 constant for user transitions and from reward.minimumstake for system transitions and rewards, and the two must match. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The design rationale promised a per-epoch limit on total paused time with a penalty "as defined in KIP-227", but KIP-227 defines none and no client keeps a paused-time total: a pause arms a fresh timeout and resume clears it. State the limit as future work and name the two bounds that do apply, so the text no longer describes an enforcement that does not exist. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The table lists what happens to a candidate that passes the VRank test and is in or out of the top 50, but a candidate whose stake fell below MinStake during testing competes for nothing: the client demotes it to ValInactive at the epoch and arms its idle deadline. Add the row so the outcome is not left to inference from the top-50 rows. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The ordering section binds the pseudocode names to the parameter table, but a reader still has to compare the two table rows to see that ValPausedSlotLimit and ValExitingSlotLimit are the same number, which is why one symbol serves both in the pseudocode. Say it there. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The configurator can lower MaxValActivePausedCount below the current ValActive and ValPaused count; nothing checks the new value against it, and no transition between epochs demotes for exceeding it. The cut happens at the next epoch, and if it would leave no ValActive the liveness floor keeps the previous set, so the count can stay above the cap for one more epoch. Say so next to the floor rule. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The note said only Council and Committee are exposed, but the client has served kaia_getNodesByState in the public kaia namespace since v3.0.0-rc.1, returning every node's state, staking amount, deadlines and suspended flag, and the method is being added to the JSON-RPC reference. Keep the consensus meaning with the two sets and name the monitoring API, so the note matches what nodes answer. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ian0371
reviewed
Oct 21, 2026
| for validator in validators: | ||
| if validator.state in (ValReady, ValInactive): | ||
| if idle_duration >= ValIdleTimeout: | ||
| if parent.timestamp >= validator.idle_deadline: |
Contributor
There was a problem hiding this comment.
As written, parent.timestamp >= validator.idle_deadline (and the equivalent pause check) expires a validator whose deadline is zero. AddressBookV2 treats timeoutAt == 0 as ‘no timeout’ (_revertIfTimeoutExpired checks timeoutAt != 0), and KIP-290 documents the same meaning. This also matches #1100, which makes zero deadlines persist without expiring.
Please specify that zero deadlines are skipped, for example: if deadline != 0 and parent.timestamp >= deadline. Apply this to both idle and pause deadlines, and clarify that the corresponding user-action checks also skip zero deadlines.
The timeout pseudocode expired a validator once parent.timestamp >= deadline, and the user-action rule reverted once block.timestamp >= deadline, so a deadline of 0 read as expired at once. The client and AddressBookV2 treat timeoutAt == 0 as no active timeout, and KIP-290 already says so. Require a nonzero deadline in both checks and define the sentinel. Every timed-state entry through the transitions still sets an absolute deadline; a zero one comes only from state written outside them, such as an initial allocation. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The invalid-message paragraph promised that the CN mesh re-establishes the link within one dial cycle. Membership only keeps both nodes eligible for discovery and dialing; whether and when the link comes back depends on reachability, admission and the dial backoff, and a peer that keeps sending invalid messages is dropped again each time. Say that, so the sentence is not read as a fixed-duration guarantee. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Chihyun Song <ian0371@gmail.com>
4 of 9 tasks
The reward paragraph said StakingInfo(N) includes every AddressBookV2 profile regardless of node state. The client builds it from getAllProfiles(), which enumerates only nodes outside the Registered state; a Registered node is kept in a separate list and has no entry. Name that set, so a reader does not expect a Registered node in kaia_getStakingInfo. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
StakingInfo(N) and kaia_getStakingInfo(N) list exactly RewardEligible(N), with parent-state amounts, reward addresses and CL entries, instead of every non-Registered profile. Follows kaia#1125. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Proposed changes
header.VRankcarriesParentRoundandParentCommittedSealwith the decoding rule and parent committee, absent beforeFORK_BLOCK; signature preimages, BLS key source and header field position;MAX_ROUNDas a protocol constant with one-byte rounds, no candidate evaluation above it, invalid messages discarded;cfReportwritten by the block author for its own most recent proposal, delivery best effort; Example 1 rewritten; the downtime requirement marked as future work.keccak256(blockHash || 0x02 || round); the block author must be a member ofqualified(N);ceil(2n/3)seal quorum and single-mode header votes; Rule 2 acts on thepfReportthat records the failure; the liveness floor and Rule 1 order; suspension as an address-keyed overlay; deadlines carried across states; the ranking stake and the twoMinStakeroles; the paused-time limit marked as future work; the CandTesting-below-MinStake row,maxSlotAvailableas the one value of both slot limits, the cap applying at the next epoch transition,kaia_getNodesByStatein the sets note; reward eligibility follows the node states for blockN, including its system transitions, while stake amounts and addresses remain sourced fromN-1; underWeightedRandom,header.Rewardbasemust match the block author's AddressBookV2 reward address, including on promotion blocks.Types of changes
Please put an x in the boxes related to your change.
Checklist
Put an x in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code.
I have read the CLA Document and I hereby sign the CLAin first time contributionRelated issues
Further comments