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.

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