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.

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