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.

293 lines
8.1 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. . "github.com/tendermint/tendermint/common"
  10. sm "github.com/tendermint/tendermint/state"
  11. "github.com/tendermint/tendermint/types"
  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 []*types.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 types.PartSetHeader
  30. maj23Exists bool
  31. }
  32. // Constructs a new VoteSet struct used to accumulate votes for given height/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_ == types.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([]*types.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. // Returns the validator index of the vote unless error is set.
  69. func (voteSet *VoteSet) Add(address []byte, vote *types.Vote) (bool, uint, error) {
  70. voteSet.mtx.Lock()
  71. defer voteSet.mtx.Unlock()
  72. // Make sure the step matches. (or that vote is commit && round < voteSet.round)
  73. if vote.Height != voteSet.height ||
  74. (vote.Type != types.VoteTypeCommit && vote.Round != voteSet.round) ||
  75. (vote.Type != types.VoteTypeCommit && vote.Type != voteSet.type_) ||
  76. (vote.Type == types.VoteTypeCommit && voteSet.type_ != types.VoteTypeCommit && vote.Round >= voteSet.round) {
  77. return false, 0, types.ErrVoteUnexpectedStep
  78. }
  79. // Ensure that signer is a validator.
  80. valIndex, val := voteSet.valSet.GetByAddress(address)
  81. if val == nil {
  82. return false, 0, types.ErrVoteInvalidAccount
  83. }
  84. // Check signature.
  85. if !val.PubKey.VerifyBytes(account.SignBytes(vote), vote.Signature) {
  86. // Bad signature.
  87. return false, 0, types.ErrVoteInvalidSignature
  88. }
  89. return voteSet.addVote(valIndex, vote)
  90. }
  91. func (voteSet *VoteSet) addVote(valIndex uint, vote *types.Vote) (bool, uint, error) {
  92. // If vote already exists, return false.
  93. if existingVote := voteSet.votes[valIndex]; existingVote != nil {
  94. if bytes.Equal(existingVote.BlockHash, vote.BlockHash) {
  95. return false, valIndex, nil
  96. } else {
  97. return false, valIndex, &types.ErrVoteConflictingSignature{
  98. VoteA: existingVote,
  99. VoteB: vote,
  100. }
  101. }
  102. }
  103. // Add vote.
  104. _, val := voteSet.valSet.GetByIndex(valIndex)
  105. if val == nil {
  106. panic(fmt.Sprintf("Missing validator for index %v", valIndex))
  107. }
  108. voteSet.votes[valIndex] = vote
  109. voteSet.votesBitArray.SetIndex(valIndex, true)
  110. blockKey := string(vote.BlockHash) + string(binary.BinaryBytes(vote.BlockParts))
  111. totalBlockHashVotes := voteSet.votesByBlock[blockKey] + val.VotingPower
  112. voteSet.votesByBlock[blockKey] = totalBlockHashVotes
  113. voteSet.totalVotes += val.VotingPower
  114. // If we just nudged it up to two thirds majority, add it.
  115. if totalBlockHashVotes > voteSet.valSet.TotalVotingPower()*2/3 &&
  116. (totalBlockHashVotes-val.VotingPower) <= voteSet.valSet.TotalVotingPower()*2/3 {
  117. voteSet.maj23Hash = vote.BlockHash
  118. voteSet.maj23Parts = vote.BlockParts
  119. voteSet.maj23Exists = true
  120. }
  121. return true, valIndex, nil
  122. }
  123. // Assumes that commits VoteSet is valid.
  124. func (voteSet *VoteSet) AddFromCommits(commits *VoteSet) {
  125. for valIndex, commit := range commits.votes {
  126. if commit == nil {
  127. continue
  128. }
  129. if commit.Round < voteSet.round {
  130. voteSet.addVote(uint(valIndex), commit)
  131. }
  132. }
  133. }
  134. func (voteSet *VoteSet) BitArray() *BitArray {
  135. if voteSet == nil {
  136. return nil
  137. }
  138. voteSet.mtx.Lock()
  139. defer voteSet.mtx.Unlock()
  140. return voteSet.votesBitArray.Copy()
  141. }
  142. func (voteSet *VoteSet) GetByIndex(valIndex uint) *types.Vote {
  143. voteSet.mtx.Lock()
  144. defer voteSet.mtx.Unlock()
  145. return voteSet.votes[valIndex]
  146. }
  147. func (voteSet *VoteSet) GetByAddress(address []byte) *types.Vote {
  148. voteSet.mtx.Lock()
  149. defer voteSet.mtx.Unlock()
  150. valIndex, val := voteSet.valSet.GetByAddress(address)
  151. if val == nil {
  152. panic("GetByAddress(address) returned nil")
  153. }
  154. return voteSet.votes[valIndex]
  155. }
  156. func (voteSet *VoteSet) HasTwoThirdsMajority() bool {
  157. if voteSet == nil {
  158. return false
  159. }
  160. voteSet.mtx.Lock()
  161. defer voteSet.mtx.Unlock()
  162. return voteSet.maj23Exists
  163. }
  164. // Returns either a blockhash (or nil) that received +2/3 majority.
  165. // If there exists no such majority, returns (nil, false).
  166. func (voteSet *VoteSet) TwoThirdsMajority() (hash []byte, parts types.PartSetHeader, ok bool) {
  167. voteSet.mtx.Lock()
  168. defer voteSet.mtx.Unlock()
  169. if voteSet.maj23Exists {
  170. return voteSet.maj23Hash, voteSet.maj23Parts, true
  171. } else {
  172. return nil, types.PartSetHeader{}, false
  173. }
  174. }
  175. func (voteSet *VoteSet) MakePOL() *POL {
  176. if voteSet.type_ != types.VoteTypePrevote {
  177. panic("Cannot MakePOL() unless VoteSet.Type is types.VoteTypePrevote")
  178. }
  179. voteSet.mtx.Lock()
  180. defer voteSet.mtx.Unlock()
  181. if !voteSet.maj23Exists {
  182. return nil
  183. }
  184. pol := &POL{
  185. Height: voteSet.height,
  186. Round: voteSet.round,
  187. BlockHash: voteSet.maj23Hash,
  188. BlockParts: voteSet.maj23Parts,
  189. Votes: make([]POLVoteSignature, voteSet.valSet.Size()),
  190. }
  191. for valIndex, vote := range voteSet.votes {
  192. if vote == nil {
  193. continue
  194. }
  195. if !bytes.Equal(vote.BlockHash, voteSet.maj23Hash) {
  196. continue
  197. }
  198. if !vote.BlockParts.Equals(voteSet.maj23Parts) {
  199. continue
  200. }
  201. pol.Votes[valIndex] = POLVoteSignature{
  202. Round: vote.Round,
  203. Signature: vote.Signature,
  204. }
  205. }
  206. return pol
  207. }
  208. func (voteSet *VoteSet) MakeValidation() *types.Validation {
  209. if voteSet.type_ != types.VoteTypeCommit {
  210. panic("Cannot MakeValidation() unless VoteSet.Type is types.VoteTypeCommit")
  211. }
  212. voteSet.mtx.Lock()
  213. defer voteSet.mtx.Unlock()
  214. if len(voteSet.maj23Hash) == 0 {
  215. panic("Cannot MakeValidation() unless a blockhash has +2/3")
  216. }
  217. commits := make([]types.Commit, voteSet.valSet.Size())
  218. voteSet.valSet.Iterate(func(valIndex uint, val *sm.Validator) bool {
  219. vote := voteSet.votes[valIndex]
  220. if vote == nil {
  221. return false
  222. }
  223. if !bytes.Equal(vote.BlockHash, voteSet.maj23Hash) {
  224. return false
  225. }
  226. if !vote.BlockParts.Equals(voteSet.maj23Parts) {
  227. return false
  228. }
  229. commits[valIndex] = types.Commit{val.Address, vote.Round, vote.Signature}
  230. return false
  231. })
  232. return &types.Validation{
  233. Commits: commits,
  234. }
  235. }
  236. func (voteSet *VoteSet) String() string {
  237. return voteSet.StringIndented("")
  238. }
  239. func (voteSet *VoteSet) StringIndented(indent string) string {
  240. voteStrings := make([]string, len(voteSet.votes))
  241. for i, vote := range voteSet.votes {
  242. if vote == nil {
  243. voteStrings[i] = "nil-Vote"
  244. } else {
  245. voteStrings[i] = vote.String()
  246. }
  247. }
  248. return fmt.Sprintf(`VoteSet{
  249. %s H:%v R:%v T:%v
  250. %s %v
  251. %s %v
  252. %s}`,
  253. indent, voteSet.height, voteSet.round, voteSet.type_,
  254. indent, strings.Join(voteStrings, "\n"+indent+" "),
  255. indent, voteSet.votesBitArray,
  256. indent)
  257. }
  258. func (voteSet *VoteSet) StringShort() string {
  259. if voteSet == nil {
  260. return "nil-VoteSet"
  261. }
  262. voteSet.mtx.Lock()
  263. defer voteSet.mtx.Unlock()
  264. return fmt.Sprintf(`VoteSet{H:%v R:%v T:%v +2/3:%v %v}`,
  265. voteSet.height, voteSet.round, voteSet.type_, voteSet.maj23Exists, voteSet.votesBitArray)
  266. }