diff --git a/common/bit_array.go b/common/bit_array.go index 119b6351f..2c8e4dada 100644 --- a/common/bit_array.go +++ b/common/bit_array.go @@ -21,14 +21,19 @@ func NewBitArray(bits uint) *BitArray { } func (bA *BitArray) Size() uint { + if bA == nil { + return 0 + } return bA.Bits } // NOTE: behavior is undefined if i >= bA.Bits func (bA *BitArray) GetIndex(i uint) bool { + if bA == nil { + return false + } bA.mtx.Lock() defer bA.mtx.Unlock() - return bA.getIndex(i) } @@ -41,9 +46,11 @@ func (bA *BitArray) getIndex(i uint) bool { // NOTE: behavior is undefined if i >= bA.Bits func (bA *BitArray) SetIndex(i uint, v bool) bool { + if bA == nil { + return false + } bA.mtx.Lock() defer bA.mtx.Unlock() - return bA.setIndex(i, v) } @@ -60,6 +67,9 @@ func (bA *BitArray) setIndex(i uint, v bool) bool { } func (bA *BitArray) Copy() *BitArray { + if bA == nil { + return nil + } bA.mtx.Lock() defer bA.mtx.Unlock() return bA.copy() @@ -85,9 +95,11 @@ func (bA *BitArray) copyBits(bits uint) *BitArray { // Returns a BitArray of larger bits size. func (bA *BitArray) Or(o *BitArray) *BitArray { + if bA == nil { + o.Copy() + } bA.mtx.Lock() defer bA.mtx.Unlock() - c := bA.copyBits(MaxUint(bA.Bits, o.Bits)) for i := 0; i < len(c.Elems); i++ { c.Elems[i] |= o.Elems[i] @@ -97,9 +109,11 @@ func (bA *BitArray) Or(o *BitArray) *BitArray { // Returns a BitArray of smaller bit size. func (bA *BitArray) And(o *BitArray) *BitArray { + if bA == nil { + return nil + } bA.mtx.Lock() defer bA.mtx.Unlock() - return bA.and(o) } @@ -112,9 +126,11 @@ func (bA *BitArray) and(o *BitArray) *BitArray { } func (bA *BitArray) Not() *BitArray { + if bA == nil { + return nil // Degenerate + } bA.mtx.Lock() defer bA.mtx.Unlock() - c := bA.copy() for i := 0; i < len(c.Elems); i++ { c.Elems[i] = ^c.Elems[i] @@ -123,9 +139,11 @@ func (bA *BitArray) Not() *BitArray { } func (bA *BitArray) Sub(o *BitArray) *BitArray { + if bA == nil { + return nil + } bA.mtx.Lock() defer bA.mtx.Unlock() - if bA.Bits > o.Bits { c := bA.copy() for i := 0; i < len(o.Elems)-1; i++ { @@ -139,11 +157,14 @@ func (bA *BitArray) Sub(o *BitArray) *BitArray { } return c } else { - return bA.and(o.Not()) + return bA.and(o.Not()) // Note degenerate case where o == nil } } func (bA *BitArray) IsFull() bool { + if bA == nil { + return true + } bA.mtx.Lock() defer bA.mtx.Unlock() @@ -165,6 +186,9 @@ func (bA *BitArray) IsFull() bool { } func (bA *BitArray) PickRandom() (uint, bool) { + if bA == nil { + return 0, false + } bA.mtx.Lock() defer bA.mtx.Unlock() @@ -210,14 +234,16 @@ func (bA *BitArray) String() string { } bA.mtx.Lock() defer bA.mtx.Unlock() - return bA.stringIndented("") } func (bA *BitArray) StringIndented(indent string) string { + if bA == nil { + return "nil-BitArray" + } bA.mtx.Lock() defer bA.mtx.Unlock() - return bA.StringIndented(indent) + return bA.stringIndented(indent) } func (bA *BitArray) stringIndented(indent string) string { diff --git a/consensus/reactor.go b/consensus/reactor.go index 4f6585b08..1bd0edba5 100644 --- a/consensus/reactor.go +++ b/consensus/reactor.go @@ -433,7 +433,6 @@ OUTER_LOOP: return } rs := conR.conS.GetRoundState() - ps.EnsureVoteBitArrays(rs.Height, rs.Validators.Size()) prs := ps.GetRoundState() switch sleeping { @@ -443,7 +442,14 @@ OUTER_LOOP: sleeping = 0 } - trySendVote := func(voteSet *VoteSet, peerVoteSet *BitArray) (sent bool) { + // Returns true when useful work was done. + trySendVote := func(height uint, voteSet *VoteSet, peerVoteSet *BitArray) (sent bool) { + if voteSet == nil { + return false + } else if peerVoteSet == nil { + ps.EnsureVoteBitArrays(height, voteSet.Size()) + return true + } // TODO: give priority to our vote. if index, ok := voteSet.BitArray().Sub(peerVoteSet.Copy()).PickRandom(); ok { vote := voteSet.GetByIndex(index) @@ -456,7 +462,14 @@ OUTER_LOOP: return false } + // Returns true when useful work was done. trySendCommitFromValidation := func(blockMeta *types.BlockMeta, validation *types.Validation, peerVoteSet *BitArray) (sent bool) { + if validation == nil { + return false + } else if peerVoteSet == nil { + ps.EnsureVoteBitArrays(blockMeta.Header.Height, uint(len(validation.Commits))) + return true + } if index, ok := validation.BitArray().Sub(prs.Commits.Copy()).PickRandom(); ok { commit := validation.Commits[index] log.Debug("Picked commit to send", "index", index, "commit", commit) @@ -482,31 +495,27 @@ OUTER_LOOP: // If there are lastcommits to send... if prs.Round == 0 && prs.Step == RoundStepNewHeight { - if prs.LastCommits != nil && rs.LastCommits != nil { - if prs.LastCommits.Size() == rs.LastCommits.Size() { - if trySendVote(rs.LastCommits, prs.LastCommits) { - continue OUTER_LOOP - } - } + if trySendVote(rs.Height-1, rs.LastCommits, prs.LastCommits) { + continue OUTER_LOOP } } // If there are prevotes to send... if rs.Round == prs.Round && prs.Step <= RoundStepPrevote { - if trySendVote(rs.Prevotes, prs.Prevotes) { + if trySendVote(rs.Height, rs.Prevotes, prs.Prevotes) { continue OUTER_LOOP } } // If there are precommits to send... if rs.Round == prs.Round && prs.Step <= RoundStepPrecommit { - if trySendVote(rs.Precommits, prs.Precommits) { + if trySendVote(rs.Height, rs.Precommits, prs.Precommits) { continue OUTER_LOOP } } // If there are any commits to send... - if trySendVote(rs.Commits, prs.Commits) { + if trySendVote(rs.Height, rs.Commits, prs.Commits) { continue OUTER_LOOP } } @@ -517,7 +526,7 @@ OUTER_LOOP: // If peer is lagging by height 1, match our LastCommits or SeenValidation to peer's Commits. if rs.Height == prs.Height+1 && rs.LastCommits.Size() > 0 { // If there are lastcommits to send... - if trySendVote(rs.LastCommits, prs.Commits) { + if trySendVote(prs.Height, rs.LastCommits, prs.Commits) { continue OUTER_LOOP } else { ps.SetHasAllCatchupCommits(prs.Height) @@ -665,18 +674,20 @@ func (ps *PeerState) EnsureVoteBitArrays(height uint, numValidators uint) { ps.mtx.Lock() defer ps.mtx.Unlock() - if ps.Height != height { - return - } - - if ps.Prevotes == nil { - ps.Prevotes = NewBitArray(numValidators) - } - if ps.Precommits == nil { - ps.Precommits = NewBitArray(numValidators) - } - if ps.Commits == nil { - ps.Commits = NewBitArray(numValidators) + if ps.Height == height { + if ps.Prevotes == nil { + ps.Prevotes = NewBitArray(numValidators) + } + if ps.Precommits == nil { + ps.Precommits = NewBitArray(numValidators) + } + if ps.Commits == nil { + ps.Commits = NewBitArray(numValidators) + } + } else if ps.Height == height+1 { + if ps.LastCommits == nil { + ps.LastCommits = NewBitArray(numValidators) + } } }