verify 된 vote를 voteSet에 추가한다. 여기선 진짜 추가함.
검증자는 r, s 각각에 대해 vote를 제출할 수 있지만 동일한 r,s에서 복수의 다른 block에 투표를 할 수는 없다.
여기서 동일한 r, s에 동일 block에 두 번 투표를 했다면 panic,
서로 다른 복수의 블록에 투표를 하려고 한다면 새로운 vote 인스턴스를 넣지 않고 vote 추가 과정을 종료하지만, 예외적으로 이미 major block이 있는 경우엔 합의 과정의 효율성을 위해 속행할 수 있음.
dir : types/vote_set.go
검증자가 이미 투표를 했는지 여부를 확인한다.
// vote 인스턴스를 보고 이 인스턴스를 생성한 validator를 확인
valIndex := vote.ValidatorIndex
if existing := voteSet.votes[valIndex]; existing != nil {
// 동일한 검증자가 동일한 block에 다시 투표를 했다면 (중복 투표) panic
if existing.BlockID.Equals(vote.BlockID) {
panic("...")
} else {
// 서로 다른 복수의 블록에 대해 투표한 경우 일단 저장
conflicting = existing
}
// voteSet에 이미 major block이 있고, 이번에 들어온 충돌하는 vote가
// 이 major block에 대한 것이라면 voteSet 안의 vote 정보를 incoming vote
// 로 업데이트 함.
if voteSet.maj23 != nil && voteSet.maj23.Key() == blockKey {
// voteSet에서 해당 validator의 vote 인스턴스 업데이트
voteSet.votes[valIndex] = vote
voteSet.votesBitArray.SetIndex(int(valIndex), true)
}
// major block에 대한 투표 이외에는 voteSet에 반영하지 않음.
// 해당 검증자가 아직 이번 round, step에서 vote를 하지 않았다면 이번 vote 인스턴스를
// voteSet에 추가한 후 voting power를 누적한다.
} else {
voteSet.votes[valIndex] = vote
voteSet.votesBitArray.SetIndex(int(valIndex), true)
voteSet.sum += votingPower
}
voteSet에서 blockID로 해당 block에 대한 vote 정보를 가져온다.
votesByBlock, ok := voteSet.votesByBlock[blockKey]
// 참고 : blockVotes type
type blockVotes struct {
peerMaj23 bool
bitArray *bits.BitArray
votes []*Vote
sum int64
}
votesByBlock의 유무에 따라 처리
// votesByBlock 인스턴스가 존재한다는 말은
// 이 블럭에 대한 vote가 incoming vote가 처음이 아님을 의미
if ok {
// conflict가 있고, 다른 검증자들에 의해 major block으로 검증되지도 않았다면
// incoming vote를 voteSet에 추가하지 않는다.
if conflicting != nil && !votesByBlock.peerMaj23 {
return false, conflicting
}
// votesByBlock 인스턴스가 없다면 이는 이 block에 대한 투표가
// 이번 incoming vote에 의해 처음 실행되는 일임을 의미함
} else {
// 이런 경우가 있을 가능성은 별로 없지만 혹시 상황이 발생하면
// 추가적인 작업을 진행하지 않고 여기서 종료
if conflicting != nil {
return false, conflicting
}
// conflicting이 없다면 새로운 votesByBlock 인스턴스를 생성해 초기화
votesByBlock = newBlockVotes(false, voteSet.valSet.Size())
voteSet.votesByBlock[blockKey] = votesByBlock
}
votesByBlock 인스턴스에 vote를 추가하고 voting power 등을 반영한다.
// 현재까지 votesByBlock에 대한 누적 voting power
origSum := votesByBlock.sum
// major block이 되기 위한 최소 voting power
quorum := voteSet.valSet.TotalVotingPower()*2/3 + 1
// votesByBlock에 vote 인스턴스 추가, voting power 반영
votesByBlock.addverifiedVote(vote, votingPower)
방금 추가한 vote로 majority를 획득했다면 maj23 값을 설정해준 후, voteSet에 모인 vote 인스턴스들을 전부 복사해줌.
if origSum < quorum && quorum <= votesByBlock.sum {
if voteSet.maj23 == nil {
maj23BlockID := vote.BlockID
voteSet.maj23 = &maj23BlockID
for i, vote := range votesByBlock.votes {
if vote != nil {
voteSet.votes[i] = vote
}
}
}
}
vote 추가 여부 리턴
return true, conflicting