Skip to content

Commit

Permalink
consensus: fix slash bug when validator set changing (bnb-chain#1162)
Browse files Browse the repository at this point in the history
  • Loading branch information
qinglin89 authored Mar 1, 2023
1 parent d065c48 commit 2a76eb4
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 7 deletions.
47 changes: 42 additions & 5 deletions consensus/parlia/parlia.go
Original file line number Diff line number Diff line change
Expand Up @@ -1298,7 +1298,7 @@ func encodeSigHeader(w io.Writer, header *types.Header, chainId *big.Int) {
}
}

func backOffTime(snap *Snapshot, val common.Address) uint64 {
func (p *Parlia) backOffTime(snap *Snapshot, header *types.Header, val common.Address) uint64 {
if snap.inturn(val) {
return 0
} else {
Expand All @@ -1311,13 +1311,50 @@ func backOffTime(snap *Snapshot, val common.Address) uint64 {
r := rand.New(s)
n := len(snap.Validators)
backOffSteps := make([]uint64, 0, n)
for idx := uint64(0); idx < uint64(n); idx++ {
backOffSteps = append(backOffSteps, idx)

if !p.chainConfig.IsBohr(header.Number) {
for i := uint64(0); i < uint64(n); i++ {
backOffSteps = append(backOffSteps, i)
}
r.Shuffle(n, func(i, j int) {
backOffSteps[i], backOffSteps[j] = backOffSteps[j], backOffSteps[i]
})
delay := initialBackOffTime + backOffSteps[idx]*wiggleTime
return delay
}

// Exclude the recently signed validators first, and then compute the backOffTime.
recentVals := make(map[common.Address]bool, len(snap.Recents))
//for seen, recent := range snap.Recents {
for _, recent := range snap.Recents {
if val == recent {
// The backOffTime does not matter when a validator has signed recently.
return 0
}
recentVals[recent] = true
}
r.Shuffle(n, func(i, j int) {

backOffIndex := idx
validators := snap.validators()
for i := 0; i < n; i++ {
if isRecent, ok := recentVals[validators[i]]; ok && isRecent {
if i < idx {
backOffIndex--
}
continue
}
backOffSteps = append(backOffSteps, uint64(len(backOffSteps)))
}
r.Shuffle(len(backOffSteps), func(i, j int) {
backOffSteps[i], backOffSteps[j] = backOffSteps[j], backOffSteps[i]
})
delay := initialBackOffTime + backOffSteps[idx]*wiggleTime
delay := initialBackOffTime + backOffSteps[backOffIndex]*wiggleTime

// If the in turn validator has recently signed, no initial delay.
inTurnVal := validators[(snap.Number+1)%uint64(len(validators))]
if isRecent, ok := recentVals[inTurnVal]; ok && isRecent {
delay -= initialBackOffTime
}
return delay
}
}
Expand Down
4 changes: 2 additions & 2 deletions consensus/parlia/ramanujanfork.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ func (p *Parlia) delayForRamanujanFork(snap *Snapshot, header *types.Header) tim
func (p *Parlia) blockTimeForRamanujanFork(snap *Snapshot, header, parent *types.Header) uint64 {
blockTime := parent.Time + p.config.Period
if p.chainConfig.IsRamanujan(header.Number) {
blockTime = blockTime + backOffTime(snap, p.val)
blockTime = blockTime + p.backOffTime(snap, header, p.val)
}
return blockTime
}

func (p *Parlia) blockTimeVerifyForRamanujanFork(snap *Snapshot, header, parent *types.Header) error {
if p.chainConfig.IsRamanujan(header.Number) {
if header.Time < parent.Time+p.config.Period+backOffTime(snap, header.Coinbase) {
if header.Time < parent.Time+p.config.Period+p.backOffTime(snap, header, header.Coinbase) {
return consensus.ErrFutureBlock
}
}
Expand Down

0 comments on commit 2a76eb4

Please sign in to comment.