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.

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