KIP 146: Unpredictable Proposer Selection
Author | Ian, Ollie, Joseph, and Aidan |
---|---|
Discussions-To | https://github.com/klaytn/kips/issues/146 |
Status | Draft |
Type | Standards Track |
Category | Core |
Created | 2023-06-15 |
Simple Summary
An unpredictable and verifiable proposer selection policy
Abstract
This standard outlines an approach for an unpredictable proposer selection policy. A proposer is determined every block in a random manner. The randomness relies on KIP-114, thereby rendering the new policy both unpredictable and verifiable.
Motivation
Klaytn has adopted the Byzantine Fault Tolerance (BFT) consensus mechanism, where a block proposer selected by a deterministic algorithm proposes the next block. A vulnerable point of BFT is that an adversary can effectively halt the entire network by simply targeting the proposer, a.k.a. targeted DoS. What makes Klaytn even more vulnerable to a targeted DoS attack is that the current proposer selection policy enables the prediction of up to proposerUpdateInterval
(3600 in case of Cypress) number of proposers in advance.
As of now, a targeted DoS is practically infeasible in Klaytn because it is a permissioned chain which allows only authorized validators to join the network. However, in a permissionless network, a targeted DoS is a viable option for attackers. A random proposer selection can increase the difficulty of the attack by introducing an uncertainty of the upcoming proposers.
Meanwhile, a few malicious validators must not be able to forge the randomness to arbitrarily determine the upcoming proposers. If not, it may increase the risk of censorship or monopolizing block rewards. Therefore, the new random proposer selection policy should be both unpredictable and verifiable.
Specification
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.
Parameters
Constant | Value |
---|---|
FORK_BLOCK |
TBD |
Shuffling
A shuffling algorithm must be defined which will act as a building block of proposer and committee selection.
Fisher-Yates shuffle must be used in the below pseudocode (i.e., random.shuffle
), and Golang’s RNG must be used as a pseudo random number generator internally in Fisher-Yates.
The shuffling function must be deterministic given validators
and seed
.
def shuffle_validators_KIP146(validators: list[int], seed: int):
"""returns a list of randomly shuffled validators.
Keyword arguments:
validators -- deterministically sorted list of validators.
seed -- `mixHash[0:8]` interpreted as the bytes of a big-endian signed 64-bit integer. The `mixHash` of the previous block is used (see KIP-114).
"""
ret = validators[:]
random.seed(seed)
random.shuffle(ret)
return ret
Proposer selection
For calculating the proposer of FORK_BLOCK
and afterward, the new logic must be used.
This only affects the chain whose proposer selection policy is set to WeightedRandom
.
Below algorithm ensures that
- The proposer must be randomly selected each block.
- The proposer must change in case of round change.
- The proposer must be selected from committee.
def proposer_selector(validators: list[int], committee_size: int, round: int, seed: int):
"""returns a proposer from validators.
Keyword arguments:
validators -- deterministically sorted list of validators.
committee_size -- the value of `istanbul.sub` in ChainConfig.
round -- the target consensus round.
seed -- `mixHash[0:8]` interpreted as the bytes of a big-endian signed 64-bit integer. The `mixHash` of the previous block is used (see KIP-114).
"""
return select_committee_KIP146(validators, committee_size, seed)[round % len(validators)]
Committee selection
For calculating the committee of FORK_BLOCK
and afterward, the new logic must be used.
This only affects the chain whose proposer selection policy is set to WeightedRandom
.
This design guarantees that the given proposer address is always in the committee.
Below algorithm ensures that
- The committee must be randomly selected each block.
- The committee must not change in case of round change.
- The next round proposer must be in the committee.
def select_committee_KIP146(validators: list[int], committee_size: int, seed: int):
"""returns a committee from validators.
Keyword arguments:
validators -- deterministically sorted list of validators.
committee_size -- the value of `istanbul.sub` in ChainConfig.
seed -- `mixHash[0:8]` interpreted as the bytes of a big-endian signed 64-bit integer. The `mixHash` of the previous block is used (see KIP-114).
"""
shuffled = shuffle_validators_KIP146(validators, seed)
return shuffled[:min(committee_size, len(validators))]
Rationale
Using part of mixHash
as a seed
As defined in KIP-114, mixHash
is the result of XOR operation with a keccak256 hash.
To the best of our knowledge, truncating the cryptographic hash is safe to be used for the seed of pseudo random number generator.
Ethereum also uses the first eight bytes of a hash: link.
Committee remaining the same in case of round change
Unlike the previous semantic of WeightedRandom
proposer selection policy, this proposal suggests a policy where the members of the committee remains the same in case of round change.
This new policy addresses a potential security issue where a fork could happen even within the number of Byzantine nodes permitted by Istanbul Byzantine Fault Tolerance mechanism (i.e., one third of validators).
Side effect
Differentiation of next round proposer and next block proposer
The current algorithm for composing a committee makes sure that the proposer and the next round proposer is included in the committee. Before FORK_BLOCK
, the next round proposer is equal to the next block proposer, and thus the next block proposer always ended up in the committee. However, after FORK_BLOCK
, the next round proposer can be different from the next block proposer, which may result in the next block proposer not being included from the committee. This side effect does not degrade the network security; while the next proposer being in the committee could potentially be helpful to next block generation, its significance is negligible, if any.
Affecting the predictability of mixHash
Allowing a certain validator to be selected as the proposer for consecutive blocks affects the predictability of mixHash
in KIP-114. See here for further details.
Backwards Compatibility
The proposer selection policy before FORK_BLOCK
remains the same.
Security Considerations
Biasability
The biasability of this proposal relies on that of KIP-114, the shuffling algorithm, and the pseudo random number generator.
- KIP-114 is unbiased because keccak256 hash is.
- The shuffling algorithm Fisher-Yates is unbiased as long as the pseudo random number generator is.
- To the best of our knowledge, the Golang’s pseudo random number generator is unbiased; it uses Additive Lagged Fibonacci Generator where initial values are generated by a Linear Congruential Generator based on the user seed.
Predictability
The probability of predicting a proposer at a certain block is the maximum of the followings:
- Predictability of
mixHash
as specified here. - Randomly picking one out of validators.
It implies that the probability has a lower bound of 1/N
, where N
is the number of validators.
Implementation
A reference implementation in Golang: link.
Note that Golang’s standard package rand.shuffle implements Fisher-Yates.
References
Copyright
Copyright and related rights waived via CC0.