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.

301 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
  1. package consensus
  2. import (
  3. "bytes"
  4. "fmt"
  5. "strings"
  6. "sync"
  7. acm "github.com/tendermint/tendermint/account"
  8. "github.com/tendermint/tendermint/wire"
  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 int
  20. round int
  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]int64 // string(blockHash)+string(blockParts) -> vote sum.
  27. totalVotes int64
  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 int, round int, type_ byte, valSet *sm.ValidatorSet) *VoteSet {
  34. if height == 0 {
  35. PanicSanity("Cannot make VoteSet for height == 0, doesn't make sense.")
  36. }
  37. return &VoteSet{
  38. height: height,
  39. round: round,
  40. type_: type_,
  41. valSet: valSet,
  42. votes: make([]*types.Vote, valSet.Size()),
  43. votesBitArray: NewBitArray(valSet.Size()),
  44. votesByBlock: make(map[string]int64),
  45. totalVotes: 0,
  46. }
  47. }
  48. func (voteSet *VoteSet) Height() int {
  49. if voteSet == nil {
  50. return 0
  51. } else {
  52. return voteSet.height
  53. }
  54. }
  55. func (voteSet *VoteSet) Round() int {
  56. if voteSet == nil {
  57. return 0
  58. } else {
  59. return voteSet.round
  60. }
  61. }
  62. func (voteSet *VoteSet) Type() byte {
  63. if voteSet == nil {
  64. return 0x00
  65. } else {
  66. return voteSet.type_
  67. }
  68. }
  69. func (voteSet *VoteSet) Size() int {
  70. if voteSet == nil {
  71. return 0
  72. } else {
  73. return voteSet.valSet.Size()
  74. }
  75. }
  76. // Returns added=true, index if vote was added
  77. // Otherwise returns err=ErrVote[UnexpectedStep|InvalidAccount|InvalidSignature|InvalidBlockHash|ConflictingSignature]
  78. // Duplicate votes return added=false, err=nil.
  79. // NOTE: vote should not be mutated after adding.
  80. func (voteSet *VoteSet) AddByIndex(valIndex int, vote *types.Vote) (added bool, index int, err error) {
  81. voteSet.mtx.Lock()
  82. defer voteSet.mtx.Unlock()
  83. return voteSet.addByIndex(valIndex, vote)
  84. }
  85. // Returns added=true, index if vote was added
  86. // Otherwise returns err=ErrVote[UnexpectedStep|InvalidAccount|InvalidSignature|InvalidBlockHash|ConflictingSignature]
  87. // Duplicate votes return added=false, err=nil.
  88. // NOTE: vote should not be mutated after adding.
  89. func (voteSet *VoteSet) AddByAddress(address []byte, vote *types.Vote) (added bool, index int, err error) {
  90. voteSet.mtx.Lock()
  91. defer voteSet.mtx.Unlock()
  92. // Ensure that signer is a validator.
  93. valIndex, val := voteSet.valSet.GetByAddress(address)
  94. if val == nil {
  95. return false, 0, types.ErrVoteInvalidAccount
  96. }
  97. return voteSet.addVote(val, valIndex, vote)
  98. }
  99. func (voteSet *VoteSet) addByIndex(valIndex int, vote *types.Vote) (bool, int, error) {
  100. // Ensure that signer is a validator.
  101. _, val := voteSet.valSet.GetByIndex(valIndex)
  102. if val == nil {
  103. return false, 0, types.ErrVoteInvalidAccount
  104. }
  105. return voteSet.addVote(val, valIndex, vote)
  106. }
  107. func (voteSet *VoteSet) addVote(val *sm.Validator, valIndex int, vote *types.Vote) (bool, int, error) {
  108. // Make sure the step matches. (or that vote is commit && round < voteSet.round)
  109. if (vote.Height != voteSet.height) ||
  110. (vote.Round != voteSet.round) ||
  111. (vote.Type != voteSet.type_) {
  112. return false, 0, types.ErrVoteUnexpectedStep
  113. }
  114. // Check signature.
  115. if !val.PubKey.VerifyBytes(acm.SignBytes(config.GetString("chain_id"), vote), vote.Signature) {
  116. // Bad signature.
  117. return false, 0, types.ErrVoteInvalidSignature
  118. }
  119. // If vote already exists, return false.
  120. if existingVote := voteSet.votes[valIndex]; existingVote != nil {
  121. if bytes.Equal(existingVote.BlockHash, vote.BlockHash) {
  122. return false, valIndex, nil
  123. } else {
  124. return false, valIndex, &types.ErrVoteConflictingSignature{
  125. VoteA: existingVote,
  126. VoteB: vote,
  127. }
  128. }
  129. }
  130. // Add vote.
  131. voteSet.votes[valIndex] = vote
  132. voteSet.votesBitArray.SetIndex(valIndex, true)
  133. blockKey := string(vote.BlockHash) + string(wire.BinaryBytes(vote.BlockParts))
  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.maj23Parts = vote.BlockParts
  142. voteSet.maj23Exists = true
  143. }
  144. return true, valIndex, 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) *types.Vote {
  155. voteSet.mtx.Lock()
  156. defer voteSet.mtx.Unlock()
  157. return voteSet.votes[valIndex]
  158. }
  159. func (voteSet *VoteSet) GetByAddress(address []byte) *types.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. voteSet.mtx.Lock()
  181. defer voteSet.mtx.Unlock()
  182. return len(voteSet.maj23Hash) > 0
  183. }
  184. func (voteSet *VoteSet) HasTwoThirdsAny() bool {
  185. if voteSet == nil {
  186. return false
  187. }
  188. voteSet.mtx.Lock()
  189. defer voteSet.mtx.Unlock()
  190. return voteSet.totalVotes > voteSet.valSet.TotalVotingPower()*2/3
  191. }
  192. // Returns either a blockhash (or nil) that received +2/3 majority.
  193. // If there exists no such majority, returns (nil, false).
  194. func (voteSet *VoteSet) TwoThirdsMajority() (hash []byte, parts types.PartSetHeader, ok bool) {
  195. voteSet.mtx.Lock()
  196. defer voteSet.mtx.Unlock()
  197. if voteSet.maj23Exists {
  198. return voteSet.maj23Hash, voteSet.maj23Parts, true
  199. } else {
  200. return nil, types.PartSetHeader{}, false
  201. }
  202. }
  203. func (voteSet *VoteSet) String() string {
  204. if voteSet == nil {
  205. return "nil-VoteSet"
  206. }
  207. return voteSet.StringIndented("")
  208. }
  209. func (voteSet *VoteSet) StringIndented(indent string) string {
  210. voteStrings := make([]string, len(voteSet.votes))
  211. for i, vote := range voteSet.votes {
  212. if vote == nil {
  213. voteStrings[i] = "nil-Vote"
  214. } else {
  215. voteStrings[i] = vote.String()
  216. }
  217. }
  218. return fmt.Sprintf(`VoteSet{
  219. %s H:%v R:%v T:%v
  220. %s %v
  221. %s %v
  222. %s}`,
  223. indent, voteSet.height, voteSet.round, voteSet.type_,
  224. indent, strings.Join(voteStrings, "\n"+indent+" "),
  225. indent, voteSet.votesBitArray,
  226. indent)
  227. }
  228. func (voteSet *VoteSet) StringShort() string {
  229. if voteSet == nil {
  230. return "nil-VoteSet"
  231. }
  232. voteSet.mtx.Lock()
  233. defer voteSet.mtx.Unlock()
  234. return fmt.Sprintf(`VoteSet{H:%v R:%v T:%v +2/3:%v %v}`,
  235. voteSet.height, voteSet.round, voteSet.type_, voteSet.maj23Exists, voteSet.votesBitArray)
  236. }
  237. //--------------------------------------------------------------------------------
  238. // Validation
  239. func (voteSet *VoteSet) MakeValidation() *types.Validation {
  240. if voteSet.type_ != types.VoteTypePrecommit {
  241. PanicSanity("Cannot MakeValidation() unless VoteSet.Type is types.VoteTypePrecommit")
  242. }
  243. voteSet.mtx.Lock()
  244. defer voteSet.mtx.Unlock()
  245. if len(voteSet.maj23Hash) == 0 {
  246. PanicSanity("Cannot MakeValidation() unless a blockhash has +2/3")
  247. }
  248. precommits := make([]*types.Vote, voteSet.valSet.Size())
  249. voteSet.valSet.Iterate(func(valIndex int, val *sm.Validator) bool {
  250. vote := voteSet.votes[valIndex]
  251. if vote == nil {
  252. return false
  253. }
  254. if !bytes.Equal(vote.BlockHash, voteSet.maj23Hash) {
  255. return false
  256. }
  257. if !vote.BlockParts.Equals(voteSet.maj23Parts) {
  258. return false
  259. }
  260. precommits[valIndex] = vote
  261. return false
  262. })
  263. return &types.Validation{
  264. Precommits: precommits,
  265. }
  266. }