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.

506 lines
14 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
  1. package types
  2. import (
  3. "bytes"
  4. "fmt"
  5. "strings"
  6. "sync"
  7. . "github.com/tendermint/go-common"
  8. )
  9. /*
  10. VoteSet helps collect signatures from validators at each height+round for a
  11. predefined vote type.
  12. We need VoteSet to be able to keep track of conflicting votes when validators
  13. double-sign. Yet, we can't keep track of *all* the votes seen, as that could
  14. be a DoS attack vector.
  15. There are two storage areas for votes.
  16. 1. voteSet.votes
  17. 2. voteSet.votesByBlock
  18. `.votes` is the "canonical" list of votes. It always has at least one vote,
  19. if a vote from a validator had been seen at all. Usually it keeps track of
  20. the first vote seen, but when a 2/3 majority is found, votes for that get
  21. priority and are copied over from `.votesByBlock`.
  22. `.votesByBlock` keeps track of a list of votes for a particular block. There
  23. are two ways a &blockVotes{} gets created in `.votesByBlock`.
  24. 1. the first vote seen by a validator was for the particular block.
  25. 2. a peer claims to have seen 2/3 majority for the particular block.
  26. Since the first vote from a validator will always get added in `.votesByBlock`
  27. , all votes in `.votes` will have a corresponding entry in `.votesByBlock`.
  28. When a &blockVotes{} in `.votesByBlock` reaches a 2/3 majority quorum, its
  29. votes are copied into `.votes`.
  30. All this is memory bounded because conflicting votes only get added if a peer
  31. told us to track that block, each peer only gets to tell us 1 such block, and,
  32. there's only a limited number of peers.
  33. NOTE: Assumes that the sum total of voting power does not exceed MaxUInt64.
  34. */
  35. type VoteSet struct {
  36. chainID string
  37. height int
  38. round int
  39. type_ byte
  40. mtx sync.Mutex
  41. valSet *ValidatorSet
  42. votesBitArray *BitArray
  43. votes []*Vote // Primary votes to share
  44. sum int64 // Sum of voting power for seen votes, discounting conflicts
  45. maj23 *BlockID // First 2/3 majority seen
  46. votesByBlock map[string]*blockVotes // string(blockHash|blockParts) -> blockVotes
  47. peerMaj23s map[string]BlockID // Maj23 for each peer
  48. }
  49. // Constructs a new VoteSet struct used to accumulate votes for given height/round.
  50. func NewVoteSet(chainID string, height int, round int, type_ byte, valSet *ValidatorSet) *VoteSet {
  51. if height == 0 {
  52. PanicSanity("Cannot make VoteSet for height == 0, doesn't make sense.")
  53. }
  54. return &VoteSet{
  55. chainID: chainID,
  56. height: height,
  57. round: round,
  58. type_: type_,
  59. valSet: valSet,
  60. votesBitArray: NewBitArray(valSet.Size()),
  61. votes: make([]*Vote, valSet.Size()),
  62. sum: 0,
  63. maj23: nil,
  64. votesByBlock: make(map[string]*blockVotes, valSet.Size()),
  65. peerMaj23s: make(map[string]BlockID),
  66. }
  67. }
  68. func (voteSet *VoteSet) ChainID() string {
  69. return voteSet.chainID
  70. }
  71. func (voteSet *VoteSet) Height() int {
  72. if voteSet == nil {
  73. return 0
  74. } else {
  75. return voteSet.height
  76. }
  77. }
  78. func (voteSet *VoteSet) Round() int {
  79. if voteSet == nil {
  80. return -1
  81. } else {
  82. return voteSet.round
  83. }
  84. }
  85. func (voteSet *VoteSet) Type() byte {
  86. if voteSet == nil {
  87. return 0x00
  88. } else {
  89. return voteSet.type_
  90. }
  91. }
  92. func (voteSet *VoteSet) Size() int {
  93. if voteSet == nil {
  94. return 0
  95. } else {
  96. return voteSet.valSet.Size()
  97. }
  98. }
  99. // Returns added=true if vote is valid and new.
  100. // Otherwise returns err=ErrVote[
  101. // UnexpectedStep | InvalidIndex | InvalidAddress |
  102. // InvalidSignature | InvalidBlockHash | ConflictingVotes ]
  103. // Duplicate votes return added=false, err=nil.
  104. // Conflicting votes return added=*, err=ErrVoteConflictingVotes.
  105. // NOTE: vote should not be mutated after adding.
  106. func (voteSet *VoteSet) AddVote(vote *Vote) (added bool, err error) {
  107. voteSet.mtx.Lock()
  108. defer voteSet.mtx.Unlock()
  109. return voteSet.addVote(vote)
  110. }
  111. // NOTE: Validates as much as possible before attempting to verify the signature.
  112. func (voteSet *VoteSet) addVote(vote *Vote) (added bool, err error) {
  113. valIndex := vote.ValidatorIndex
  114. valAddr := vote.ValidatorAddress
  115. blockKey := vote.BlockID.Key()
  116. // Ensure that validator index was set
  117. if valIndex < 0 || len(valAddr) == 0 {
  118. panic("Validator index or address was not set in vote.")
  119. }
  120. // Make sure the step matches.
  121. if (vote.Height != voteSet.height) ||
  122. (vote.Round != voteSet.round) ||
  123. (vote.Type != voteSet.type_) {
  124. return false, ErrVoteUnexpectedStep
  125. }
  126. // Ensure that signer is a validator.
  127. lookupAddr, val := voteSet.valSet.GetByIndex(valIndex)
  128. if val == nil {
  129. return false, ErrVoteInvalidValidatorIndex
  130. }
  131. // Ensure that the signer has the right address
  132. if !bytes.Equal(valAddr, lookupAddr) {
  133. return false, ErrVoteInvalidValidatorAddress
  134. }
  135. // If we already know of this vote, return false.
  136. if existing, ok := voteSet.getVote(valIndex, blockKey); ok {
  137. if existing.Signature.Equals(vote.Signature) {
  138. return false, nil // duplicate
  139. } else {
  140. return false, ErrVoteInvalidSignature // NOTE: assumes deterministic signatures
  141. }
  142. }
  143. // Check signature.
  144. if !val.PubKey.VerifyBytes(SignBytes(voteSet.chainID, vote), vote.Signature) {
  145. // Bad signature.
  146. return false, ErrVoteInvalidSignature
  147. }
  148. // Add vote and get conflicting vote if any
  149. added, conflicting := voteSet.addVerifiedVote(vote, blockKey, val.VotingPower)
  150. if conflicting != nil {
  151. return added, &ErrVoteConflictingVotes{
  152. VoteA: conflicting,
  153. VoteB: vote,
  154. }
  155. } else {
  156. if !added {
  157. PanicSanity("Expected to add non-conflicting vote")
  158. }
  159. return added, nil
  160. }
  161. }
  162. // Returns (vote, true) if vote exists for valIndex and blockKey
  163. func (voteSet *VoteSet) getVote(valIndex int, blockKey string) (vote *Vote, ok bool) {
  164. if existing := voteSet.votes[valIndex]; existing != nil && existing.BlockID.Key() == blockKey {
  165. return existing, true
  166. }
  167. if existing := voteSet.votesByBlock[blockKey].getByIndex(valIndex); existing != nil {
  168. return existing, true
  169. }
  170. return nil, false
  171. }
  172. // Assumes signature is valid.
  173. // If conflicting vote exists, returns it.
  174. func (voteSet *VoteSet) addVerifiedVote(vote *Vote, blockKey string, votingPower int64) (added bool, conflicting *Vote) {
  175. valIndex := vote.ValidatorIndex
  176. // Already exists in voteSet.votes?
  177. if existing := voteSet.votes[valIndex]; existing != nil {
  178. if existing.BlockID.Equals(vote.BlockID) {
  179. PanicSanity("addVerifiedVote does not expect duplicate votes")
  180. } else {
  181. conflicting = existing
  182. }
  183. // Replace vote if blockKey matches voteSet.maj23.
  184. if voteSet.maj23 != nil && voteSet.maj23.Key() == blockKey {
  185. voteSet.votes[valIndex] = vote
  186. voteSet.votesBitArray.SetIndex(valIndex, true)
  187. }
  188. // Otherwise don't add it to voteSet.votes
  189. } else {
  190. // Add to voteSet.votes and incr .sum
  191. voteSet.votes[valIndex] = vote
  192. voteSet.votesBitArray.SetIndex(valIndex, true)
  193. voteSet.sum += votingPower
  194. }
  195. votesByBlock, ok := voteSet.votesByBlock[blockKey]
  196. if ok {
  197. if conflicting != nil && !votesByBlock.peerMaj23 {
  198. // There's a conflict and no peer claims that this block is special.
  199. return false, conflicting
  200. }
  201. // We'll add the vote in a bit.
  202. } else {
  203. // .votesByBlock doesn't exist...
  204. if conflicting != nil {
  205. // ... and there's a conflicting vote.
  206. // We're not even tracking this blockKey, so just forget it.
  207. return false, conflicting
  208. } else {
  209. // ... and there's no conflicting vote.
  210. // Start tracking this blockKey
  211. votesByBlock = newBlockVotes(false, voteSet.valSet.Size())
  212. voteSet.votesByBlock[blockKey] = votesByBlock
  213. // We'll add the vote in a bit.
  214. }
  215. }
  216. // Before adding to votesByBlock, see if we'll exceed quorum
  217. origSum := votesByBlock.sum
  218. quorum := voteSet.valSet.TotalVotingPower()*2/3 + 1
  219. // Add vote to votesByBlock
  220. votesByBlock.addVerifiedVote(vote, votingPower)
  221. // If we just crossed the quorum threshold and have 2/3 majority...
  222. if origSum < quorum && quorum <= votesByBlock.sum {
  223. // Only consider the first quorum reached
  224. if voteSet.maj23 == nil {
  225. maj23BlockID := vote.BlockID
  226. voteSet.maj23 = &maj23BlockID
  227. // And also copy votes over to voteSet.votes
  228. for i, vote := range votesByBlock.votes {
  229. if vote != nil {
  230. voteSet.votes[i] = vote
  231. }
  232. }
  233. }
  234. }
  235. return true, conflicting
  236. }
  237. // If a peer claims that it has 2/3 majority for given blockKey, call this.
  238. // NOTE: if there are too many peers, or too much peer churn,
  239. // this can cause memory issues.
  240. // TODO: implement ability to remove peers too
  241. func (voteSet *VoteSet) SetPeerMaj23(peerID string, blockID BlockID) {
  242. voteSet.mtx.Lock()
  243. defer voteSet.mtx.Unlock()
  244. blockKey := blockID.Key()
  245. // Make sure peer hasn't already told us something.
  246. if existing, ok := voteSet.peerMaj23s[peerID]; ok {
  247. if existing.Equals(blockID) {
  248. return // Nothing to do
  249. } else {
  250. return // TODO bad peer!
  251. }
  252. }
  253. voteSet.peerMaj23s[peerID] = blockID
  254. // Create .votesByBlock entry if needed.
  255. votesByBlock, ok := voteSet.votesByBlock[blockKey]
  256. if ok {
  257. if votesByBlock.peerMaj23 {
  258. return // Nothing to do
  259. } else {
  260. votesByBlock.peerMaj23 = true
  261. // No need to copy votes, already there.
  262. }
  263. } else {
  264. votesByBlock = newBlockVotes(true, voteSet.valSet.Size())
  265. voteSet.votesByBlock[blockKey] = votesByBlock
  266. // No need to copy votes, no votes to copy over.
  267. }
  268. }
  269. func (voteSet *VoteSet) BitArray() *BitArray {
  270. if voteSet == nil {
  271. return nil
  272. }
  273. voteSet.mtx.Lock()
  274. defer voteSet.mtx.Unlock()
  275. return voteSet.votesBitArray.Copy()
  276. }
  277. func (voteSet *VoteSet) BitArrayByBlockID(blockID BlockID) *BitArray {
  278. if voteSet == nil {
  279. return nil
  280. }
  281. voteSet.mtx.Lock()
  282. defer voteSet.mtx.Unlock()
  283. votesByBlock, ok := voteSet.votesByBlock[blockID.Key()]
  284. if ok {
  285. return votesByBlock.bitArray
  286. }
  287. return nil
  288. }
  289. // NOTE: if validator has conflicting votes, returns "canonical" vote
  290. func (voteSet *VoteSet) GetByIndex(valIndex int) *Vote {
  291. voteSet.mtx.Lock()
  292. defer voteSet.mtx.Unlock()
  293. return voteSet.votes[valIndex]
  294. }
  295. func (voteSet *VoteSet) GetByAddress(address []byte) *Vote {
  296. voteSet.mtx.Lock()
  297. defer voteSet.mtx.Unlock()
  298. valIndex, val := voteSet.valSet.GetByAddress(address)
  299. if val == nil {
  300. PanicSanity("GetByAddress(address) returned nil")
  301. }
  302. return voteSet.votes[valIndex]
  303. }
  304. func (voteSet *VoteSet) HasTwoThirdsMajority() bool {
  305. if voteSet == nil {
  306. return false
  307. }
  308. voteSet.mtx.Lock()
  309. defer voteSet.mtx.Unlock()
  310. return voteSet.maj23 != nil
  311. }
  312. func (voteSet *VoteSet) IsCommit() bool {
  313. if voteSet == nil {
  314. return false
  315. }
  316. if voteSet.type_ != VoteTypePrecommit {
  317. return false
  318. }
  319. voteSet.mtx.Lock()
  320. defer voteSet.mtx.Unlock()
  321. return voteSet.maj23 != nil
  322. }
  323. func (voteSet *VoteSet) HasTwoThirdsAny() bool {
  324. if voteSet == nil {
  325. return false
  326. }
  327. voteSet.mtx.Lock()
  328. defer voteSet.mtx.Unlock()
  329. return voteSet.sum > voteSet.valSet.TotalVotingPower()*2/3
  330. }
  331. // Returns either a blockhash (or nil) that received +2/3 majority.
  332. // If there exists no such majority, returns (nil, PartSetHeader{}, false).
  333. func (voteSet *VoteSet) TwoThirdsMajority() (blockID BlockID, ok bool) {
  334. voteSet.mtx.Lock()
  335. defer voteSet.mtx.Unlock()
  336. if voteSet.maj23 != nil {
  337. return *voteSet.maj23, true
  338. } else {
  339. return BlockID{}, false
  340. }
  341. }
  342. func (voteSet *VoteSet) String() string {
  343. if voteSet == nil {
  344. return "nil-VoteSet"
  345. }
  346. return voteSet.StringIndented("")
  347. }
  348. func (voteSet *VoteSet) StringIndented(indent string) string {
  349. voteStrings := make([]string, len(voteSet.votes))
  350. for i, vote := range voteSet.votes {
  351. if vote == nil {
  352. voteStrings[i] = "nil-Vote"
  353. } else {
  354. voteStrings[i] = vote.String()
  355. }
  356. }
  357. return fmt.Sprintf(`VoteSet{
  358. %s H:%v R:%v T:%v
  359. %s %v
  360. %s %v
  361. %s %v
  362. %s}`,
  363. indent, voteSet.height, voteSet.round, voteSet.type_,
  364. indent, strings.Join(voteStrings, "\n"+indent+" "),
  365. indent, voteSet.votesBitArray,
  366. indent, voteSet.peerMaj23s,
  367. indent)
  368. }
  369. func (voteSet *VoteSet) StringShort() string {
  370. if voteSet == nil {
  371. return "nil-VoteSet"
  372. }
  373. voteSet.mtx.Lock()
  374. defer voteSet.mtx.Unlock()
  375. return fmt.Sprintf(`VoteSet{H:%v R:%v T:%v +2/3:%v %v %v}`,
  376. voteSet.height, voteSet.round, voteSet.type_, voteSet.maj23, voteSet.votesBitArray, voteSet.peerMaj23s)
  377. }
  378. //--------------------------------------------------------------------------------
  379. // Commit
  380. func (voteSet *VoteSet) MakeCommit() *Commit {
  381. if voteSet.type_ != VoteTypePrecommit {
  382. PanicSanity("Cannot MakeCommit() unless VoteSet.Type is VoteTypePrecommit")
  383. }
  384. voteSet.mtx.Lock()
  385. defer voteSet.mtx.Unlock()
  386. // Make sure we have a 2/3 majority
  387. if voteSet.maj23 == nil {
  388. PanicSanity("Cannot MakeCommit() unless a blockhash has +2/3")
  389. }
  390. // For every validator, get the precommit
  391. votesCopy := make([]*Vote, len(voteSet.votes))
  392. copy(votesCopy, voteSet.votes)
  393. return &Commit{
  394. BlockID: *voteSet.maj23,
  395. Precommits: votesCopy,
  396. }
  397. }
  398. //--------------------------------------------------------------------------------
  399. /*
  400. Votes for a particular block
  401. There are two ways a *blockVotes gets created for a blockKey.
  402. 1. first (non-conflicting) vote of a validator w/ blockKey (peerMaj23=false)
  403. 2. A peer claims to have a 2/3 majority w/ blockKey (peerMaj23=true)
  404. */
  405. type blockVotes struct {
  406. peerMaj23 bool // peer claims to have maj23
  407. bitArray *BitArray // valIndex -> hasVote?
  408. votes []*Vote // valIndex -> *Vote
  409. sum int64 // vote sum
  410. }
  411. func newBlockVotes(peerMaj23 bool, numValidators int) *blockVotes {
  412. return &blockVotes{
  413. peerMaj23: peerMaj23,
  414. bitArray: NewBitArray(numValidators),
  415. votes: make([]*Vote, numValidators),
  416. sum: 0,
  417. }
  418. }
  419. func (vs *blockVotes) addVerifiedVote(vote *Vote, votingPower int64) {
  420. valIndex := vote.ValidatorIndex
  421. if existing := vs.votes[valIndex]; existing == nil {
  422. vs.bitArray.SetIndex(valIndex, true)
  423. vs.votes[valIndex] = vote
  424. vs.sum += votingPower
  425. }
  426. }
  427. func (vs *blockVotes) getByIndex(index int) *Vote {
  428. if vs == nil {
  429. return nil
  430. }
  431. return vs.votes[index]
  432. }
  433. //--------------------------------------------------------------------------------
  434. // Common interface between *consensus.VoteSet and types.Commit
  435. type VoteSetReader interface {
  436. Height() int
  437. Round() int
  438. Type() byte
  439. Size() int
  440. BitArray() *BitArray
  441. GetByIndex(int) *Vote
  442. IsCommit() bool
  443. }