fix bitArray nil bugs
This commit is contained in:
parent
ba17961269
commit
6020223e85
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
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,10 +674,7 @@ func (ps *PeerState) EnsureVoteBitArrays(height uint, numValidators uint) {
|
|||
ps.mtx.Lock()
|
||||
defer ps.mtx.Unlock()
|
||||
|
||||
if ps.Height != height {
|
||||
return
|
||||
}
|
||||
|
||||
if ps.Height == height {
|
||||
if ps.Prevotes == nil {
|
||||
ps.Prevotes = NewBitArray(numValidators)
|
||||
}
|
||||
|
@ -678,6 +684,11 @@ func (ps *PeerState) EnsureVoteBitArrays(height uint, numValidators uint) {
|
|||
if ps.Commits == nil {
|
||||
ps.Commits = NewBitArray(numValidators)
|
||||
}
|
||||
} else if ps.Height == height+1 {
|
||||
if ps.LastCommits == nil {
|
||||
ps.LastCommits = NewBitArray(numValidators)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ps *PeerState) SetHasVote(vote *types.Vote, index uint) {
|
||||
|
|
Loading…
Reference in New Issue