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.

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