mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 06:42:16 +00:00
Removed MinValidTime Round0 exception; WiggleR -> WiggleDelta
This commit is contained in:
parent
b4120e25ff
commit
4ec86eea39
@ -396,9 +396,9 @@ type ConsensusConfig struct {
|
|||||||
PeerQueryMaj23SleepDuration int `mapstructure:"peer_query_maj23_sleep_duration"`
|
PeerQueryMaj23SleepDuration int `mapstructure:"peer_query_maj23_sleep_duration"`
|
||||||
|
|
||||||
// Block time parameters in milliseconds
|
// Block time parameters in milliseconds
|
||||||
BlockTimeIota int `mapstructure:"blocktime_iota"`
|
BlockTimeIota int `mapstructure:"blocktime_iota"`
|
||||||
BlockTimeWiggle int `mapstructure:"blocktime_wiggle"`
|
BlockTimeWiggle int `mapstructure:"blocktime_wiggle"`
|
||||||
BlockTimeWiggleR float64 `mapstructure:"blocktime_wiggle_r"`
|
BlockTimeWiggleDelta int `mapstructure:"blocktime_wiggle_delta"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultConsensusConfig returns a default configuration for the consensus service
|
// DefaultConsensusConfig returns a default configuration for the consensus service
|
||||||
@ -421,7 +421,7 @@ func DefaultConsensusConfig() *ConsensusConfig {
|
|||||||
PeerQueryMaj23SleepDuration: 2000,
|
PeerQueryMaj23SleepDuration: 2000,
|
||||||
BlockTimeIota: 10,
|
BlockTimeIota: 10,
|
||||||
BlockTimeWiggle: 20000,
|
BlockTimeWiggle: 20000,
|
||||||
BlockTimeWiggleR: 0.05,
|
BlockTimeWiggleDelta: 1000,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,27 +487,19 @@ func (cfg *ConsensusConfig) PeerQueryMaj23Sleep() time.Duration {
|
|||||||
|
|
||||||
// BlockTimeMinValidTime returns the minimum acceptable block time, as part
|
// BlockTimeMinValidTime returns the minimum acceptable block time, as part
|
||||||
// of "subjective time validity". See the BFT time spec.
|
// of "subjective time validity". See the BFT time spec.
|
||||||
func (cfg *ConsensusConfig) BlockTimeMinValidTime(lastBlockTime, now time.Time, round int) time.Time {
|
func (cfg *ConsensusConfig) BlockTimeMinValidTime(lastBlockTime time.Time) time.Time {
|
||||||
var minValidTime time.Time = lastBlockTime.Add(time.Duration(cfg.BlockTimeIota) * time.Millisecond)
|
return lastBlockTime.
|
||||||
if round == 0 {
|
Add(time.Duration(cfg.BlockTimeIota) * time.Millisecond)
|
||||||
wiggleAgo := now.Add(-1 * time.Duration(cfg.BlockTimeWiggle) * time.Millisecond)
|
|
||||||
if wiggleAgo.After(minValidTime) {
|
|
||||||
minValidTime = wiggleAgo
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// For all subsequent rounds, we accept any block > last_block_time+iota.
|
|
||||||
}
|
|
||||||
return minValidTime
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlockTimeMaxValidTime returns the maximum acceptable block time, as part
|
// BlockTimeMaxValidTime returns the maximum acceptable block time, as part
|
||||||
// of "subjective time validity". See the BFT time spec.
|
// of "subjective time validity". See the BFT time spec.
|
||||||
func (cfg *ConsensusConfig) BlockTimeMaxValidTime(lastBlockTime, now time.Time, round int) time.Time {
|
func (cfg *ConsensusConfig) BlockTimeMaxValidTime(now time.Time, round int) time.Time {
|
||||||
return now.
|
return now.
|
||||||
Add(time.Duration(cfg.BlockTimeWiggle) * time.Millisecond).
|
Add(time.Duration(cfg.BlockTimeWiggle) * time.Millisecond).
|
||||||
Add(
|
Add(
|
||||||
time.Duration(
|
time.Duration(
|
||||||
float64(cfg.BlockTimeWiggle)*cfg.BlockTimeWiggleR*float64(round),
|
int64(cfg.BlockTimeWiggleDelta)*int64(round),
|
||||||
) * time.Millisecond,
|
) * time.Millisecond,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -945,7 +945,7 @@ func (cs *ConsensusState) defaultDoPrevote(height int64, round int) {
|
|||||||
// See the BFT time spec.
|
// See the BFT time spec.
|
||||||
lastBlockTime := cs.state.LastBlockTime
|
lastBlockTime := cs.state.LastBlockTime
|
||||||
now := time.Now().Round(0).UTC()
|
now := time.Now().Round(0).UTC()
|
||||||
minValidTime := cs.config.BlockTimeMinValidTime(lastBlockTime, now, round)
|
minValidTime := cs.config.BlockTimeMinValidTime(lastBlockTime)
|
||||||
if cs.ProposalBlock.Time.Before(minValidTime) {
|
if cs.ProposalBlock.Time.Before(minValidTime) {
|
||||||
logger.Info("enterPrevote: ProposalBlock time too low",
|
logger.Info("enterPrevote: ProposalBlock time too low",
|
||||||
"blockTime", cs.ProposalBlock.Time,
|
"blockTime", cs.ProposalBlock.Time,
|
||||||
@ -953,7 +953,7 @@ func (cs *ConsensusState) defaultDoPrevote(height int64, round int) {
|
|||||||
cs.signAddVote(types.VoteTypePrevote, nil, types.PartSetHeader{})
|
cs.signAddVote(types.VoteTypePrevote, nil, types.PartSetHeader{})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
maxValidTime := cs.config.BlockTimeMaxValidTime(lastBlockTime, now, round)
|
maxValidTime := cs.config.BlockTimeMaxValidTime(now, round)
|
||||||
if maxValidTime.Before(cs.ProposalBlock.Time) {
|
if maxValidTime.Before(cs.ProposalBlock.Time) {
|
||||||
logger.Info("enterPrevote: ProposalBlock time too high",
|
logger.Info("enterPrevote: ProposalBlock time too high",
|
||||||
"blockTime", cs.ProposalBlock.Time,
|
"blockTime", cs.ProposalBlock.Time,
|
||||||
|
@ -13,55 +13,49 @@ a header H1 for height h1 and a header H2 for height `h2 = h1 + 1`, `H1.Time < H
|
|||||||
Beyond satisfying time monotinicity, Tendermint also checks the following
|
Beyond satisfying time monotinicity, Tendermint also checks the following
|
||||||
property, but only when signing a prevote for a block:
|
property, but only when signing a prevote for a block:
|
||||||
|
|
||||||
- **Subjective Time Validity**: Time is greater than MinValidTime(last_block_time,
|
- **Subjective Time Validity**: Time is greater than MinValidTime(last_block_time) and less than or equal to MaxValidTime(now, round), where:
|
||||||
now, round) and less than or equal to MaxValidTime(last_block_time, now), where:
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// wiggle and iota are provided by consensus config.
|
// iota provided by consensus config.
|
||||||
func MinValidTime(last_block_time, now time.Time, round int) time.Time {
|
func MinValidTime(last_block_time) time.Time {
|
||||||
var minValidTime time.Time = last_block_time.Add(iota)
|
return lastBlockTime.
|
||||||
if round == 0 {
|
Add(time.Duration(iota) * time.Millisecond)
|
||||||
minValidTime = maxTime(minValidTime, now.Add(-1*wiggle)
|
|
||||||
} else {
|
|
||||||
// For all subsequent rounds, we accept any block > last_block_time+iota.
|
|
||||||
}
|
|
||||||
return minValidTime
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// wiggle and wiggle_r are provided by consensus config.
|
// wiggle and wiggle_delta are provided by consensus config.
|
||||||
func MaxValidTime(last_block_time, now time.Time, round int) time.Time {
|
func MaxValidTime(now time.Time, round int) time.Time {
|
||||||
return now.
|
return now.
|
||||||
Add(wiggle).
|
Add(time.Duration(wiggle) * time.Millisecond).
|
||||||
Add(wiggle*wiggle_r*round)
|
Add(
|
||||||
|
time.Duration(
|
||||||
|
wiggle_delta*float64(round),
|
||||||
|
) * time.Millisecond,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
For `MinValidTime`, we only accept recent blocks (`wiggle`) on the first
|
For `MinValidTime`, we accept any block that is at least `iota` greater than
|
||||||
round. This has the effect of slightly slowing down the blockchain (requiring
|
the last block time. Blocks that are significantly older than the current time
|
||||||
at least two rounds of consensus instead of one) progressively as more validator
|
can still be valid, which allows for the re-proposing of older proposals.
|
||||||
clocks get off sync from each other. Blocks that are significantly older than
|
|
||||||
`now` can still be valid (except in round 0), which allows for the re-proposing of older proposals.
|
|
||||||
The blockchain's time "eventually" catches up over block heights to a reasonably recent time as long as
|
|
||||||
time-correct validators' proposals are committed in a timely fashion (i.e. less than 1/3
|
|
||||||
are Byzantine) TODO: Quantify "eventually" as a function of % of time-correct
|
|
||||||
validators.
|
|
||||||
|
|
||||||
For `MaxValidTime`, we accept blocks where the block time is greater than `now`
|
For `MaxValidTime`, we accept block times greater than `now` plus some
|
||||||
plus some threshold that increases linearly with the round number.
|
threshold that increases linearly with the round number. The purpose of
|
||||||
The purpose of `wiggle_r` is for graceful degredation when +2/3 validators
|
`wiggle_delta` is for graceful degredation when +2/3 validators *aren't* within
|
||||||
*aren't* within `wiggle` of each other but are otherwise non-Byzantine in all other respects.
|
`wiggle` of each other but are otherwise non-Byzantine in all other respects.
|
||||||
Consider an example with 100 equally weighted validators, where 33 are Byzantine,
|
|
||||||
and one of the remaining 67 validators has a faulty clock that causes it to drift
|
|
||||||
back more than `wiggle` from the other 66. If the 33 Byzantine
|
|
||||||
validators were to withhold their votes, no block would produce a Polka until the
|
|
||||||
drifting one becomes the proposer!
|
|
||||||
|
|
||||||
NOTE: `wiggle_r` could be set to something like 0.05 (e.g. if `wiggle` were 20s, `wiggle*wiggle_r` would be 1s.)
|
Consider an example with 100 equally weighted validators, where 33 are
|
||||||
`wiggle*wiggle_r` should probably be less than `timeout_propose_delta` to prevent unnecessary
|
Byzantine, and one of the remaining 67 validators has a faulty clock that
|
||||||
forward time-jumps in cases where higher rounds are reached due to factors
|
causes it to drift back more than `wiggle` from the other 66. Without
|
||||||
other than network performance -- for example, where the network is performant
|
`wiggle_delta`, if the 33 Byzantine validators were to withhold their votes, no
|
||||||
but several proposers were absent in a row. `wiggle_r` could theoretically be set to 0
|
block would produce a Polka until the drifting one becomes the proposer.
|
||||||
if it can be assumed that +2/3 (by voting power) of correct validators' clocks are within `wiggle` of each other.
|
|
||||||
|
NOTE: `wiggle_delta` should probably be less than `timeout_propose_delta` to
|
||||||
|
prevent unnecessary forward time-jumps in cases where higher rounds are reached
|
||||||
|
due to factors other than network performance -- for example, where the network
|
||||||
|
is performant but several proposers were absent in a row. `wiggle_delta` could
|
||||||
|
theoretically be set to 0 if it can be assumed that +2/3 (by voting power) of
|
||||||
|
correct validators' clocks are within `wiggle` of each other.
|
||||||
|
|
||||||
Subjective time validity is ignored when a Polka or Commit is found, allowing
|
Subjective time validity is ignored when a Polka or Commit is found, allowing
|
||||||
consensus to progress locally even when the subjective time requirements are not satisfied.
|
consensus to progress locally even when the subjective time requirements are
|
||||||
|
not satisfied.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user