You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

280 lines
7.6 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. package consensus
  2. import (
  3. "bytes"
  4. "fmt"
  5. "strings"
  6. "sync"
  7. . "github.com/tendermint/tendermint/account"
  8. . "github.com/tendermint/tendermint/binary"
  9. . "github.com/tendermint/tendermint/block"
  10. "github.com/tendermint/tendermint/state"
  11. )
  12. // VoteSet helps collect signatures from validators at each height+round
  13. // for a predefined vote type.
  14. // Note that there three kinds of votes: prevotes, precommits, and commits.
  15. // A commit of prior rounds can be added added in lieu of votes/precommits.
  16. // NOTE: Assumes that the sum total of voting power does not exceed MaxUInt64.
  17. type VoteSet struct {
  18. height uint
  19. round uint
  20. type_ byte
  21. mtx sync.Mutex
  22. valSet *state.ValidatorSet
  23. votes []*Vote // validator index -> vote
  24. votesBitArray BitArray // validator index -> has vote?
  25. votesByBlock map[string]uint64 // string(blockHash)+string(blockParts) -> vote sum.
  26. totalVotes uint64
  27. maj23Hash []byte
  28. maj23Parts PartSetHeader
  29. maj23Exists bool
  30. }
  31. // Constructs a new VoteSet struct used to accumulate votes for each round.
  32. func NewVoteSet(height uint, round uint, type_ byte, valSet *state.ValidatorSet) *VoteSet {
  33. if height == 0 {
  34. panic("Cannot make VoteSet for height == 0, doesn't make sense.")
  35. }
  36. if type_ == VoteTypeCommit && round != 0 {
  37. panic("Expected round 0 for commit vote set")
  38. }
  39. return &VoteSet{
  40. height: height,
  41. round: round,
  42. type_: type_,
  43. valSet: valSet,
  44. votes: make([]*Vote, valSet.Size()),
  45. votesBitArray: NewBitArray(valSet.Size()),
  46. votesByBlock: make(map[string]uint64),
  47. totalVotes: 0,
  48. }
  49. }
  50. func (voteSet *VoteSet) Size() uint {
  51. if voteSet == nil {
  52. return 0
  53. } else {
  54. return voteSet.valSet.Size()
  55. }
  56. }
  57. // True if added, false if not.
  58. // Returns ErrVote[UnexpectedStep|InvalidAccount|InvalidSignature|InvalidBlockHash|ConflictingSignature]
  59. // NOTE: vote should not be mutated after adding.
  60. func (voteSet *VoteSet) Add(address []byte, vote *Vote) (bool, uint, error) {
  61. voteSet.mtx.Lock()
  62. defer voteSet.mtx.Unlock()
  63. // Make sure the step matches. (or that vote is commit && round < voteSet.round)
  64. if vote.Height != voteSet.height ||
  65. (vote.Type != VoteTypeCommit && vote.Round != voteSet.round) ||
  66. (vote.Type != VoteTypeCommit && vote.Type != voteSet.type_) ||
  67. (vote.Type == VoteTypeCommit && voteSet.type_ != VoteTypeCommit && vote.Round >= voteSet.round) {
  68. return false, 0, ErrVoteUnexpectedStep
  69. }
  70. // Ensure that signer is a validator.
  71. valIndex, val := voteSet.valSet.GetByAddress(address)
  72. if val == nil {
  73. return false, 0, ErrVoteInvalidAccount
  74. }
  75. // Check signature.
  76. if !val.PubKey.VerifyBytes(SignBytes(vote), vote.Signature) {
  77. // Bad signature.
  78. return false, 0, ErrVoteInvalidSignature
  79. }
  80. return voteSet.addVote(valIndex, vote)
  81. }
  82. func (voteSet *VoteSet) addVote(valIndex uint, vote *Vote) (bool, uint, error) {
  83. // If vote already exists, return false.
  84. if existingVote := voteSet.votes[valIndex]; existingVote != nil {
  85. if bytes.Equal(existingVote.BlockHash, vote.BlockHash) {
  86. return false, 0, nil
  87. } else {
  88. return false, 0, ErrVoteConflictingSignature
  89. }
  90. }
  91. // Add vote.
  92. _, val := voteSet.valSet.GetByIndex(valIndex)
  93. if val == nil {
  94. panic(fmt.Sprintf("Missing validator for index %v", valIndex))
  95. }
  96. voteSet.votes[valIndex] = vote
  97. voteSet.votesBitArray.SetIndex(valIndex, true)
  98. blockKey := string(vote.BlockHash) + string(BinaryBytes(vote.BlockParts))
  99. totalBlockHashVotes := voteSet.votesByBlock[blockKey] + val.VotingPower
  100. voteSet.votesByBlock[blockKey] = totalBlockHashVotes
  101. voteSet.totalVotes += val.VotingPower
  102. // If we just nudged it up to two thirds majority, add it.
  103. if totalBlockHashVotes > voteSet.valSet.TotalVotingPower()*2/3 &&
  104. (totalBlockHashVotes-val.VotingPower) <= voteSet.valSet.TotalVotingPower()*2/3 {
  105. voteSet.maj23Hash = vote.BlockHash
  106. voteSet.maj23Parts = vote.BlockParts
  107. voteSet.maj23Exists = true
  108. }
  109. return true, valIndex, nil
  110. }
  111. // Assumes that commits VoteSet is valid.
  112. func (voteSet *VoteSet) AddFromCommits(commits *VoteSet) {
  113. for valIndex, commit := range commits.votes {
  114. if commit == nil {
  115. continue
  116. }
  117. if commit.Round < voteSet.round {
  118. voteSet.addVote(uint(valIndex), commit)
  119. }
  120. }
  121. }
  122. func (voteSet *VoteSet) BitArray() BitArray {
  123. if voteSet == nil {
  124. return BitArray{}
  125. }
  126. voteSet.mtx.Lock()
  127. defer voteSet.mtx.Unlock()
  128. return voteSet.votesBitArray.Copy()
  129. }
  130. func (voteSet *VoteSet) GetByIndex(valIndex uint) *Vote {
  131. voteSet.mtx.Lock()
  132. defer voteSet.mtx.Unlock()
  133. return voteSet.votes[valIndex]
  134. }
  135. func (voteSet *VoteSet) GetByAddress(address []byte) *Vote {
  136. voteSet.mtx.Lock()
  137. defer voteSet.mtx.Unlock()
  138. valIndex, val := voteSet.valSet.GetByAddress(address)
  139. if val == nil {
  140. panic("GetByAddress(address) returned nil")
  141. }
  142. return voteSet.votes[valIndex]
  143. }
  144. func (voteSet *VoteSet) HasTwoThirdsMajority() bool {
  145. if voteSet == nil {
  146. return false
  147. }
  148. voteSet.mtx.Lock()
  149. defer voteSet.mtx.Unlock()
  150. return voteSet.maj23Exists
  151. }
  152. // Returns either a blockhash (or nil) that received +2/3 majority.
  153. // If there exists no such majority, returns (nil, false).
  154. func (voteSet *VoteSet) TwoThirdsMajority() (hash []byte, parts PartSetHeader, ok bool) {
  155. voteSet.mtx.Lock()
  156. defer voteSet.mtx.Unlock()
  157. if voteSet.maj23Exists {
  158. return voteSet.maj23Hash, voteSet.maj23Parts, true
  159. } else {
  160. return nil, PartSetHeader{}, false
  161. }
  162. }
  163. func (voteSet *VoteSet) MakePOL() *POL {
  164. if voteSet.type_ != VoteTypePrevote {
  165. panic("Cannot MakePOL() unless VoteSet.Type is VoteTypePrevote")
  166. }
  167. voteSet.mtx.Lock()
  168. defer voteSet.mtx.Unlock()
  169. if !voteSet.maj23Exists {
  170. return nil
  171. }
  172. pol := &POL{
  173. Height: voteSet.height,
  174. Round: voteSet.round,
  175. BlockHash: voteSet.maj23Hash,
  176. BlockParts: voteSet.maj23Parts,
  177. Votes: make([]POLVoteSignature, voteSet.valSet.Size()),
  178. }
  179. for valIndex, vote := range voteSet.votes {
  180. if vote == nil {
  181. continue
  182. }
  183. if !bytes.Equal(vote.BlockHash, voteSet.maj23Hash) {
  184. continue
  185. }
  186. if !vote.BlockParts.Equals(voteSet.maj23Parts) {
  187. continue
  188. }
  189. pol.Votes[valIndex] = POLVoteSignature{
  190. Round: vote.Round,
  191. Signature: vote.Signature,
  192. }
  193. }
  194. return pol
  195. }
  196. func (voteSet *VoteSet) MakeValidation() *Validation {
  197. if voteSet.type_ != VoteTypeCommit {
  198. panic("Cannot MakeValidation() unless VoteSet.Type is VoteTypeCommit")
  199. }
  200. voteSet.mtx.Lock()
  201. defer voteSet.mtx.Unlock()
  202. if len(voteSet.maj23Hash) == 0 {
  203. panic("Cannot MakeValidation() unless a blockhash has +2/3")
  204. }
  205. commits := make([]Commit, voteSet.valSet.Size())
  206. voteSet.valSet.Iterate(func(valIndex uint, val *state.Validator) bool {
  207. vote := voteSet.votes[valIndex]
  208. if vote == nil {
  209. return false
  210. }
  211. if !bytes.Equal(vote.BlockHash, voteSet.maj23Hash) {
  212. return false
  213. }
  214. if !vote.BlockParts.Equals(voteSet.maj23Parts) {
  215. return false
  216. }
  217. commits[valIndex] = Commit{val.Address, vote.Round, vote.Signature}
  218. return false
  219. })
  220. return &Validation{
  221. Commits: commits,
  222. }
  223. }
  224. func (voteSet *VoteSet) String() string {
  225. return voteSet.StringIndented("")
  226. }
  227. func (voteSet *VoteSet) StringIndented(indent string) string {
  228. voteStrings := make([]string, len(voteSet.votes))
  229. for i, vote := range voteSet.votes {
  230. if vote == nil {
  231. voteStrings[i] = "nil-Vote"
  232. } else {
  233. voteStrings[i] = vote.String()
  234. }
  235. }
  236. return fmt.Sprintf(`VoteSet{
  237. %s H:%v R:%v T:%v
  238. %s %v
  239. %s %v
  240. %s}`,
  241. indent, voteSet.height, voteSet.round, voteSet.type_,
  242. indent, strings.Join(voteStrings, "\n"+indent+" "),
  243. indent, voteSet.votesBitArray,
  244. indent)
  245. }
  246. func (voteSet *VoteSet) StringShort() string {
  247. if voteSet == nil {
  248. return "nil-VoteSet"
  249. }
  250. voteSet.mtx.Lock()
  251. defer voteSet.mtx.Unlock()
  252. return fmt.Sprintf(`VoteSet{H:%v R:%v T:%v %v}`,
  253. voteSet.height, voteSet.round, voteSet.type_, voteSet.votesBitArray)
  254. }