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.

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