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.

624 lines
18 KiB

10 years ago
10 years ago
10 years ago
10 years ago
lint: Enable Golint (#4212) * Fix many golint errors * Fix golint errors in the 'lite' package * Don't export Pool.store * Fix typo * Revert unwanted changes * Fix errors in counter package * Fix linter errors in kvstore package * Fix linter error in example package * Fix error in tests package * Fix linter errors in v2 package * Fix linter errors in consensus package * Fix linter errors in evidence package * Fix linter error in fail package * Fix linter errors in query package * Fix linter errors in core package * Fix linter errors in node package * Fix linter errors in mempool package * Fix linter error in conn package * Fix linter errors in pex package * Rename PEXReactor export to Reactor * Fix linter errors in trust package * Fix linter errors in upnp package * Fix linter errors in p2p package * Fix linter errors in proxy package * Fix linter errors in mock_test package * Fix linter error in client_test package * Fix linter errors in coretypes package * Fix linter errors in coregrpc package * Fix linter errors in rpcserver package * Fix linter errors in rpctypes package * Fix linter errors in rpctest package * Fix linter error in json2wal script * Fix linter error in wal2json script * Fix linter errors in kv package * Fix linter error in state package * Fix linter error in grpc_client * Fix linter errors in types package * Fix linter error in version package * Fix remaining errors * Address review comments * Fix broken tests * Reconcile package coregrpc * Fix golangci bot error * Fix new golint errors * Fix broken reference * Enable golint linter * minor changes to bring golint into line * fix failing test * fix pex reactor naming * address PR comments
5 years ago
10 years ago
10 years ago
lint: Enable Golint (#4212) * Fix many golint errors * Fix golint errors in the 'lite' package * Don't export Pool.store * Fix typo * Revert unwanted changes * Fix errors in counter package * Fix linter errors in kvstore package * Fix linter error in example package * Fix error in tests package * Fix linter errors in v2 package * Fix linter errors in consensus package * Fix linter errors in evidence package * Fix linter error in fail package * Fix linter errors in query package * Fix linter errors in core package * Fix linter errors in node package * Fix linter errors in mempool package * Fix linter error in conn package * Fix linter errors in pex package * Rename PEXReactor export to Reactor * Fix linter errors in trust package * Fix linter errors in upnp package * Fix linter errors in p2p package * Fix linter errors in proxy package * Fix linter errors in mock_test package * Fix linter error in client_test package * Fix linter errors in coretypes package * Fix linter errors in coregrpc package * Fix linter errors in rpcserver package * Fix linter errors in rpctypes package * Fix linter errors in rpctest package * Fix linter error in json2wal script * Fix linter error in wal2json script * Fix linter errors in kv package * Fix linter error in state package * Fix linter error in grpc_client * Fix linter errors in types package * Fix linter error in version package * Fix remaining errors * Address review comments * Fix broken tests * Reconcile package coregrpc * Fix golangci bot error * Fix new golint errors * Fix broken reference * Enable golint linter * minor changes to bring golint into line * fix failing test * fix pex reactor naming * address PR comments
5 years ago
10 years ago
10 years ago
10 years ago
10 years ago
lint: Enable Golint (#4212) * Fix many golint errors * Fix golint errors in the 'lite' package * Don't export Pool.store * Fix typo * Revert unwanted changes * Fix errors in counter package * Fix linter errors in kvstore package * Fix linter error in example package * Fix error in tests package * Fix linter errors in v2 package * Fix linter errors in consensus package * Fix linter errors in evidence package * Fix linter error in fail package * Fix linter errors in query package * Fix linter errors in core package * Fix linter errors in node package * Fix linter errors in mempool package * Fix linter error in conn package * Fix linter errors in pex package * Rename PEXReactor export to Reactor * Fix linter errors in trust package * Fix linter errors in upnp package * Fix linter errors in p2p package * Fix linter errors in proxy package * Fix linter errors in mock_test package * Fix linter error in client_test package * Fix linter errors in coretypes package * Fix linter errors in coregrpc package * Fix linter errors in rpcserver package * Fix linter errors in rpctypes package * Fix linter errors in rpctest package * Fix linter error in json2wal script * Fix linter error in wal2json script * Fix linter errors in kv package * Fix linter error in state package * Fix linter error in grpc_client * Fix linter errors in types package * Fix linter error in version package * Fix remaining errors * Address review comments * Fix broken tests * Reconcile package coregrpc * Fix golangci bot error * Fix new golint errors * Fix broken reference * Enable golint linter * minor changes to bring golint into line * fix failing test * fix pex reactor naming * address PR comments
5 years ago
10 years ago
lint: Enable Golint (#4212) * Fix many golint errors * Fix golint errors in the 'lite' package * Don't export Pool.store * Fix typo * Revert unwanted changes * Fix errors in counter package * Fix linter errors in kvstore package * Fix linter error in example package * Fix error in tests package * Fix linter errors in v2 package * Fix linter errors in consensus package * Fix linter errors in evidence package * Fix linter error in fail package * Fix linter errors in query package * Fix linter errors in core package * Fix linter errors in node package * Fix linter errors in mempool package * Fix linter error in conn package * Fix linter errors in pex package * Rename PEXReactor export to Reactor * Fix linter errors in trust package * Fix linter errors in upnp package * Fix linter errors in p2p package * Fix linter errors in proxy package * Fix linter errors in mock_test package * Fix linter error in client_test package * Fix linter errors in coretypes package * Fix linter errors in coregrpc package * Fix linter errors in rpcserver package * Fix linter errors in rpctypes package * Fix linter errors in rpctest package * Fix linter error in json2wal script * Fix linter error in wal2json script * Fix linter errors in kv package * Fix linter error in state package * Fix linter error in grpc_client * Fix linter errors in types package * Fix linter error in version package * Fix remaining errors * Address review comments * Fix broken tests * Reconcile package coregrpc * Fix golangci bot error * Fix new golint errors * Fix broken reference * Enable golint linter * minor changes to bring golint into line * fix failing test * fix pex reactor naming * address PR comments
5 years ago
10 years ago
8 years ago
8 years ago
8 years ago
10 years ago
lint: Enable Golint (#4212) * Fix many golint errors * Fix golint errors in the 'lite' package * Don't export Pool.store * Fix typo * Revert unwanted changes * Fix errors in counter package * Fix linter errors in kvstore package * Fix linter error in example package * Fix error in tests package * Fix linter errors in v2 package * Fix linter errors in consensus package * Fix linter errors in evidence package * Fix linter error in fail package * Fix linter errors in query package * Fix linter errors in core package * Fix linter errors in node package * Fix linter errors in mempool package * Fix linter error in conn package * Fix linter errors in pex package * Rename PEXReactor export to Reactor * Fix linter errors in trust package * Fix linter errors in upnp package * Fix linter errors in p2p package * Fix linter errors in proxy package * Fix linter errors in mock_test package * Fix linter error in client_test package * Fix linter errors in coretypes package * Fix linter errors in coregrpc package * Fix linter errors in rpcserver package * Fix linter errors in rpctypes package * Fix linter errors in rpctest package * Fix linter error in json2wal script * Fix linter error in wal2json script * Fix linter errors in kv package * Fix linter error in state package * Fix linter error in grpc_client * Fix linter errors in types package * Fix linter error in version package * Fix remaining errors * Address review comments * Fix broken tests * Reconcile package coregrpc * Fix golangci bot error * Fix new golint errors * Fix broken reference * Enable golint linter * minor changes to bring golint into line * fix failing test * fix pex reactor naming * address PR comments
5 years ago
lint: Enable Golint (#4212) * Fix many golint errors * Fix golint errors in the 'lite' package * Don't export Pool.store * Fix typo * Revert unwanted changes * Fix errors in counter package * Fix linter errors in kvstore package * Fix linter error in example package * Fix error in tests package * Fix linter errors in v2 package * Fix linter errors in consensus package * Fix linter errors in evidence package * Fix linter error in fail package * Fix linter errors in query package * Fix linter errors in core package * Fix linter errors in node package * Fix linter errors in mempool package * Fix linter error in conn package * Fix linter errors in pex package * Rename PEXReactor export to Reactor * Fix linter errors in trust package * Fix linter errors in upnp package * Fix linter errors in p2p package * Fix linter errors in proxy package * Fix linter errors in mock_test package * Fix linter error in client_test package * Fix linter errors in coretypes package * Fix linter errors in coregrpc package * Fix linter errors in rpcserver package * Fix linter errors in rpctypes package * Fix linter errors in rpctest package * Fix linter error in json2wal script * Fix linter error in wal2json script * Fix linter errors in kv package * Fix linter error in state package * Fix linter error in grpc_client * Fix linter errors in types package * Fix linter error in version package * Fix remaining errors * Address review comments * Fix broken tests * Reconcile package coregrpc * Fix golangci bot error * Fix new golint errors * Fix broken reference * Enable golint linter * minor changes to bring golint into line * fix failing test * fix pex reactor naming * address PR comments
5 years ago
10 years ago
10 years ago
10 years ago
8 years ago
8 years ago
8 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
8 years ago
10 years ago
8 years ago
10 years ago
10 years ago
lint: Enable Golint (#4212) * Fix many golint errors * Fix golint errors in the 'lite' package * Don't export Pool.store * Fix typo * Revert unwanted changes * Fix errors in counter package * Fix linter errors in kvstore package * Fix linter error in example package * Fix error in tests package * Fix linter errors in v2 package * Fix linter errors in consensus package * Fix linter errors in evidence package * Fix linter error in fail package * Fix linter errors in query package * Fix linter errors in core package * Fix linter errors in node package * Fix linter errors in mempool package * Fix linter error in conn package * Fix linter errors in pex package * Rename PEXReactor export to Reactor * Fix linter errors in trust package * Fix linter errors in upnp package * Fix linter errors in p2p package * Fix linter errors in proxy package * Fix linter errors in mock_test package * Fix linter error in client_test package * Fix linter errors in coretypes package * Fix linter errors in coregrpc package * Fix linter errors in rpcserver package * Fix linter errors in rpctypes package * Fix linter errors in rpctest package * Fix linter error in json2wal script * Fix linter error in wal2json script * Fix linter errors in kv package * Fix linter error in state package * Fix linter error in grpc_client * Fix linter errors in types package * Fix linter error in version package * Fix remaining errors * Address review comments * Fix broken tests * Reconcile package coregrpc * Fix golangci bot error * Fix new golint errors * Fix broken reference * Enable golint linter * minor changes to bring golint into line * fix failing test * fix pex reactor naming * address PR comments
5 years ago
8 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
lint: Enable Golint (#4212) * Fix many golint errors * Fix golint errors in the 'lite' package * Don't export Pool.store * Fix typo * Revert unwanted changes * Fix errors in counter package * Fix linter errors in kvstore package * Fix linter error in example package * Fix error in tests package * Fix linter errors in v2 package * Fix linter errors in consensus package * Fix linter errors in evidence package * Fix linter error in fail package * Fix linter errors in query package * Fix linter errors in core package * Fix linter errors in node package * Fix linter errors in mempool package * Fix linter error in conn package * Fix linter errors in pex package * Rename PEXReactor export to Reactor * Fix linter errors in trust package * Fix linter errors in upnp package * Fix linter errors in p2p package * Fix linter errors in proxy package * Fix linter errors in mock_test package * Fix linter error in client_test package * Fix linter errors in coretypes package * Fix linter errors in coregrpc package * Fix linter errors in rpcserver package * Fix linter errors in rpctypes package * Fix linter errors in rpctest package * Fix linter error in json2wal script * Fix linter error in wal2json script * Fix linter errors in kv package * Fix linter error in state package * Fix linter error in grpc_client * Fix linter errors in types package * Fix linter error in version package * Fix remaining errors * Address review comments * Fix broken tests * Reconcile package coregrpc * Fix golangci bot error * Fix new golint errors * Fix broken reference * Enable golint linter * minor changes to bring golint into line * fix failing test * fix pex reactor naming * address PR comments
5 years ago
lint: Enable Golint (#4212) * Fix many golint errors * Fix golint errors in the 'lite' package * Don't export Pool.store * Fix typo * Revert unwanted changes * Fix errors in counter package * Fix linter errors in kvstore package * Fix linter error in example package * Fix error in tests package * Fix linter errors in v2 package * Fix linter errors in consensus package * Fix linter errors in evidence package * Fix linter error in fail package * Fix linter errors in query package * Fix linter errors in core package * Fix linter errors in node package * Fix linter errors in mempool package * Fix linter error in conn package * Fix linter errors in pex package * Rename PEXReactor export to Reactor * Fix linter errors in trust package * Fix linter errors in upnp package * Fix linter errors in p2p package * Fix linter errors in proxy package * Fix linter errors in mock_test package * Fix linter error in client_test package * Fix linter errors in coretypes package * Fix linter errors in coregrpc package * Fix linter errors in rpcserver package * Fix linter errors in rpctypes package * Fix linter errors in rpctest package * Fix linter error in json2wal script * Fix linter error in wal2json script * Fix linter errors in kv package * Fix linter error in state package * Fix linter error in grpc_client * Fix linter errors in types package * Fix linter error in version package * Fix remaining errors * Address review comments * Fix broken tests * Reconcile package coregrpc * Fix golangci bot error * Fix new golint errors * Fix broken reference * Enable golint linter * minor changes to bring golint into line * fix failing test * fix pex reactor naming * address PR comments
5 years ago
lint: Enable Golint (#4212) * Fix many golint errors * Fix golint errors in the 'lite' package * Don't export Pool.store * Fix typo * Revert unwanted changes * Fix errors in counter package * Fix linter errors in kvstore package * Fix linter error in example package * Fix error in tests package * Fix linter errors in v2 package * Fix linter errors in consensus package * Fix linter errors in evidence package * Fix linter error in fail package * Fix linter errors in query package * Fix linter errors in core package * Fix linter errors in node package * Fix linter errors in mempool package * Fix linter error in conn package * Fix linter errors in pex package * Rename PEXReactor export to Reactor * Fix linter errors in trust package * Fix linter errors in upnp package * Fix linter errors in p2p package * Fix linter errors in proxy package * Fix linter errors in mock_test package * Fix linter error in client_test package * Fix linter errors in coretypes package * Fix linter errors in coregrpc package * Fix linter errors in rpcserver package * Fix linter errors in rpctypes package * Fix linter errors in rpctest package * Fix linter error in json2wal script * Fix linter error in wal2json script * Fix linter errors in kv package * Fix linter error in state package * Fix linter error in grpc_client * Fix linter errors in types package * Fix linter error in version package * Fix remaining errors * Address review comments * Fix broken tests * Reconcile package coregrpc * Fix golangci bot error * Fix new golint errors * Fix broken reference * Enable golint linter * minor changes to bring golint into line * fix failing test * fix pex reactor naming * address PR comments
5 years ago
lint: Enable Golint (#4212) * Fix many golint errors * Fix golint errors in the 'lite' package * Don't export Pool.store * Fix typo * Revert unwanted changes * Fix errors in counter package * Fix linter errors in kvstore package * Fix linter error in example package * Fix error in tests package * Fix linter errors in v2 package * Fix linter errors in consensus package * Fix linter errors in evidence package * Fix linter error in fail package * Fix linter errors in query package * Fix linter errors in core package * Fix linter errors in node package * Fix linter errors in mempool package * Fix linter error in conn package * Fix linter errors in pex package * Rename PEXReactor export to Reactor * Fix linter errors in trust package * Fix linter errors in upnp package * Fix linter errors in p2p package * Fix linter errors in proxy package * Fix linter errors in mock_test package * Fix linter error in client_test package * Fix linter errors in coretypes package * Fix linter errors in coregrpc package * Fix linter errors in rpcserver package * Fix linter errors in rpctypes package * Fix linter errors in rpctest package * Fix linter error in json2wal script * Fix linter error in wal2json script * Fix linter errors in kv package * Fix linter error in state package * Fix linter error in grpc_client * Fix linter errors in types package * Fix linter error in version package * Fix remaining errors * Address review comments * Fix broken tests * Reconcile package coregrpc * Fix golangci bot error * Fix new golint errors * Fix broken reference * Enable golint linter * minor changes to bring golint into line * fix failing test * fix pex reactor naming * address PR comments
5 years ago
  1. package types
  2. import (
  3. "bytes"
  4. "fmt"
  5. "strings"
  6. "sync"
  7. "github.com/tendermint/tendermint/libs/bits"
  8. )
  9. const (
  10. // MaxVotesCount is the maximum number of votes in a set. Used in ValidateBasic funcs for
  11. // protection against DOS attacks. Note this implies a corresponding equal limit to
  12. // the number of validators.
  13. MaxVotesCount = 10000
  14. )
  15. // UNSTABLE
  16. // XXX: duplicate of p2p.ID to avoid dependence between packages.
  17. // Perhaps we can have a minimal types package containing this (and other things?)
  18. // that both `types` and `p2p` import ?
  19. type P2PID string
  20. /*
  21. VoteSet helps collect signatures from validators at each height+round for a
  22. predefined vote type.
  23. We need VoteSet to be able to keep track of conflicting votes when validators
  24. double-sign. Yet, we can't keep track of *all* the votes seen, as that could
  25. be a DoS attack vector.
  26. There are two storage areas for votes.
  27. 1. voteSet.votes
  28. 2. voteSet.votesByBlock
  29. `.votes` is the "canonical" list of votes. It always has at least one vote,
  30. if a vote from a validator had been seen at all. Usually it keeps track of
  31. the first vote seen, but when a 2/3 majority is found, votes for that get
  32. priority and are copied over from `.votesByBlock`.
  33. `.votesByBlock` keeps track of a list of votes for a particular block. There
  34. are two ways a &blockVotes{} gets created in `.votesByBlock`.
  35. 1. the first vote seen by a validator was for the particular block.
  36. 2. a peer claims to have seen 2/3 majority for the particular block.
  37. Since the first vote from a validator will always get added in `.votesByBlock`
  38. , all votes in `.votes` will have a corresponding entry in `.votesByBlock`.
  39. When a &blockVotes{} in `.votesByBlock` reaches a 2/3 majority quorum, its
  40. votes are copied into `.votes`.
  41. All this is memory bounded because conflicting votes only get added if a peer
  42. told us to track that block, each peer only gets to tell us 1 such block, and,
  43. there's only a limited number of peers.
  44. NOTE: Assumes that the sum total of voting power does not exceed MaxUInt64.
  45. */
  46. type VoteSet struct {
  47. chainID string
  48. height int64
  49. round int
  50. signedMsgType SignedMsgType
  51. valSet *ValidatorSet
  52. mtx sync.Mutex
  53. votesBitArray *bits.BitArray
  54. votes []*Vote // Primary votes to share
  55. sum int64 // Sum of voting power for seen votes, discounting conflicts
  56. maj23 *BlockID // First 2/3 majority seen
  57. votesByBlock map[string]*blockVotes // string(blockHash|blockParts) -> blockVotes
  58. peerMaj23s map[P2PID]BlockID // Maj23 for each peer
  59. }
  60. // Constructs a new VoteSet struct used to accumulate votes for given height/round.
  61. func NewVoteSet(chainID string, height int64, round int, signedMsgType SignedMsgType, valSet *ValidatorSet) *VoteSet {
  62. if height == 0 {
  63. panic("Cannot make VoteSet for height == 0, doesn't make sense.")
  64. }
  65. return &VoteSet{
  66. chainID: chainID,
  67. height: height,
  68. round: round,
  69. signedMsgType: signedMsgType,
  70. valSet: valSet,
  71. votesBitArray: bits.NewBitArray(valSet.Size()),
  72. votes: make([]*Vote, valSet.Size()),
  73. sum: 0,
  74. maj23: nil,
  75. votesByBlock: make(map[string]*blockVotes, valSet.Size()),
  76. peerMaj23s: make(map[P2PID]BlockID),
  77. }
  78. }
  79. func (voteSet *VoteSet) ChainID() string {
  80. return voteSet.chainID
  81. }
  82. // Implements VoteSetReader.
  83. func (voteSet *VoteSet) GetHeight() int64 {
  84. if voteSet == nil {
  85. return 0
  86. }
  87. return voteSet.height
  88. }
  89. // Implements VoteSetReader.
  90. func (voteSet *VoteSet) GetRound() int {
  91. if voteSet == nil {
  92. return -1
  93. }
  94. return voteSet.round
  95. }
  96. // Implements VoteSetReader.
  97. func (voteSet *VoteSet) Type() byte {
  98. if voteSet == nil {
  99. return 0x00
  100. }
  101. return byte(voteSet.signedMsgType)
  102. }
  103. // Implements VoteSetReader.
  104. func (voteSet *VoteSet) Size() int {
  105. if voteSet == nil {
  106. return 0
  107. }
  108. return voteSet.valSet.Size()
  109. }
  110. // Returns added=true if vote is valid and new.
  111. // Otherwise returns err=ErrVote[
  112. // UnexpectedStep | InvalidIndex | InvalidAddress |
  113. // InvalidSignature | InvalidBlockHash | ConflictingVotes ]
  114. // Duplicate votes return added=false, err=nil.
  115. // Conflicting votes return added=*, err=ErrVoteConflictingVotes.
  116. // NOTE: vote should not be mutated after adding.
  117. // NOTE: VoteSet must not be nil
  118. // NOTE: Vote must not be nil
  119. func (voteSet *VoteSet) AddVote(vote *Vote) (added bool, err error) {
  120. if voteSet == nil {
  121. panic("AddVote() on nil VoteSet")
  122. }
  123. voteSet.mtx.Lock()
  124. defer voteSet.mtx.Unlock()
  125. return voteSet.addVote(vote)
  126. }
  127. // NOTE: Validates as much as possible before attempting to verify the signature.
  128. func (voteSet *VoteSet) addVote(vote *Vote) (added bool, err error) {
  129. if vote == nil {
  130. return false, ErrVoteNil
  131. }
  132. valIndex := vote.ValidatorIndex
  133. valAddr := vote.ValidatorAddress
  134. blockKey := vote.BlockID.Key()
  135. // Ensure that validator index was set
  136. if valIndex < 0 {
  137. return false, fmt.Errorf("index < 0: %w", ErrVoteInvalidValidatorIndex)
  138. } else if len(valAddr) == 0 {
  139. return false, fmt.Errorf("empty address: %w", ErrVoteInvalidValidatorAddress)
  140. }
  141. // Make sure the step matches.
  142. if (vote.Height != voteSet.height) ||
  143. (vote.Round != voteSet.round) ||
  144. (vote.Type != voteSet.signedMsgType) {
  145. return false, fmt.Errorf("expected %d/%d/%d, but got %d/%d/%d: %w",
  146. voteSet.height, voteSet.round, voteSet.signedMsgType,
  147. vote.Height, vote.Round, vote.Type, ErrVoteUnexpectedStep)
  148. }
  149. // Ensure that signer is a validator.
  150. lookupAddr, val := voteSet.valSet.GetByIndex(valIndex)
  151. if val == nil {
  152. return false, fmt.Errorf(
  153. "cannot find validator %d in valSet of size %d: %w",
  154. valIndex, voteSet.valSet.Size(), ErrVoteInvalidValidatorIndex)
  155. }
  156. // Ensure that the signer has the right address.
  157. if !bytes.Equal(valAddr, lookupAddr) {
  158. return false, fmt.Errorf(
  159. "vote.ValidatorAddress (%X) does not match address (%X) for vote.ValidatorIndex (%d)\n"+
  160. "Ensure the genesis file is correct across all validators: %w",
  161. valAddr, lookupAddr, valIndex, ErrVoteInvalidValidatorAddress)
  162. }
  163. // If we already know of this vote, return false.
  164. if existing, ok := voteSet.getVote(valIndex, blockKey); ok {
  165. if bytes.Equal(existing.Signature, vote.Signature) {
  166. return false, nil // duplicate
  167. }
  168. return false, fmt.Errorf("existing vote: %v; new vote: %v: %w", existing, vote, ErrVoteNonDeterministicSignature)
  169. }
  170. // Check signature.
  171. if err := vote.Verify(voteSet.chainID, val.PubKey); err != nil {
  172. return false, fmt.Errorf("failed to verify vote with ChainID %s and PubKey %s: %w", voteSet.chainID, val.PubKey, err)
  173. }
  174. // Add vote and get conflicting vote if any.
  175. added, conflicting := voteSet.addVerifiedVote(vote, blockKey, val.VotingPower)
  176. if conflicting != nil {
  177. return added, NewConflictingVoteError(val, conflicting, vote)
  178. }
  179. if !added {
  180. panic("Expected to add non-conflicting vote")
  181. }
  182. return added, nil
  183. }
  184. // Returns (vote, true) if vote exists for valIndex and blockKey.
  185. func (voteSet *VoteSet) getVote(valIndex int, blockKey string) (vote *Vote, ok bool) {
  186. if existing := voteSet.votes[valIndex]; existing != nil && existing.BlockID.Key() == blockKey {
  187. return existing, true
  188. }
  189. if existing := voteSet.votesByBlock[blockKey].getByIndex(valIndex); existing != nil {
  190. return existing, true
  191. }
  192. return nil, false
  193. }
  194. // Assumes signature is valid.
  195. // If conflicting vote exists, returns it.
  196. func (voteSet *VoteSet) addVerifiedVote(
  197. vote *Vote,
  198. blockKey string,
  199. votingPower int64,
  200. ) (added bool, conflicting *Vote) {
  201. valIndex := vote.ValidatorIndex
  202. // Already exists in voteSet.votes?
  203. if existing := voteSet.votes[valIndex]; existing != nil {
  204. if existing.BlockID.Equals(vote.BlockID) {
  205. panic("addVerifiedVote does not expect duplicate votes")
  206. } else {
  207. conflicting = existing
  208. }
  209. // Replace vote if blockKey matches voteSet.maj23.
  210. if voteSet.maj23 != nil && voteSet.maj23.Key() == blockKey {
  211. voteSet.votes[valIndex] = vote
  212. voteSet.votesBitArray.SetIndex(valIndex, true)
  213. }
  214. // Otherwise don't add it to voteSet.votes
  215. } else {
  216. // Add to voteSet.votes and incr .sum
  217. voteSet.votes[valIndex] = vote
  218. voteSet.votesBitArray.SetIndex(valIndex, true)
  219. voteSet.sum += votingPower
  220. }
  221. votesByBlock, ok := voteSet.votesByBlock[blockKey]
  222. if ok {
  223. if conflicting != nil && !votesByBlock.peerMaj23 {
  224. // There's a conflict and no peer claims that this block is special.
  225. return false, conflicting
  226. }
  227. // We'll add the vote in a bit.
  228. } else {
  229. // .votesByBlock doesn't exist...
  230. if conflicting != nil {
  231. // ... and there's a conflicting vote.
  232. // We're not even tracking this blockKey, so just forget it.
  233. return false, conflicting
  234. }
  235. // ... and there's no conflicting vote.
  236. // Start tracking this blockKey
  237. votesByBlock = newBlockVotes(false, voteSet.valSet.Size())
  238. voteSet.votesByBlock[blockKey] = votesByBlock
  239. // We'll add the vote in a bit.
  240. }
  241. // Before adding to votesByBlock, see if we'll exceed quorum
  242. origSum := votesByBlock.sum
  243. quorum := voteSet.valSet.TotalVotingPower()*2/3 + 1
  244. // Add vote to votesByBlock
  245. votesByBlock.addVerifiedVote(vote, votingPower)
  246. // If we just crossed the quorum threshold and have 2/3 majority...
  247. if origSum < quorum && quorum <= votesByBlock.sum {
  248. // Only consider the first quorum reached
  249. if voteSet.maj23 == nil {
  250. maj23BlockID := vote.BlockID
  251. voteSet.maj23 = &maj23BlockID
  252. // And also copy votes over to voteSet.votes
  253. for i, vote := range votesByBlock.votes {
  254. if vote != nil {
  255. voteSet.votes[i] = vote
  256. }
  257. }
  258. }
  259. }
  260. return true, conflicting
  261. }
  262. // If a peer claims that it has 2/3 majority for given blockKey, call this.
  263. // NOTE: if there are too many peers, or too much peer churn,
  264. // this can cause memory issues.
  265. // TODO: implement ability to remove peers too
  266. // NOTE: VoteSet must not be nil
  267. func (voteSet *VoteSet) SetPeerMaj23(peerID P2PID, blockID BlockID) error {
  268. if voteSet == nil {
  269. panic("SetPeerMaj23() on nil VoteSet")
  270. }
  271. voteSet.mtx.Lock()
  272. defer voteSet.mtx.Unlock()
  273. blockKey := blockID.Key()
  274. // Make sure peer hasn't already told us something.
  275. if existing, ok := voteSet.peerMaj23s[peerID]; ok {
  276. if existing.Equals(blockID) {
  277. return nil // Nothing to do
  278. }
  279. return fmt.Errorf("setPeerMaj23: Received conflicting blockID from peer %v. Got %v, expected %v",
  280. peerID, blockID, existing)
  281. }
  282. voteSet.peerMaj23s[peerID] = blockID
  283. // Create .votesByBlock entry if needed.
  284. votesByBlock, ok := voteSet.votesByBlock[blockKey]
  285. if ok {
  286. if votesByBlock.peerMaj23 {
  287. return nil // Nothing to do
  288. }
  289. votesByBlock.peerMaj23 = true
  290. // No need to copy votes, already there.
  291. } else {
  292. votesByBlock = newBlockVotes(true, voteSet.valSet.Size())
  293. voteSet.votesByBlock[blockKey] = votesByBlock
  294. // No need to copy votes, no votes to copy over.
  295. }
  296. return nil
  297. }
  298. // Implements VoteSetReader.
  299. func (voteSet *VoteSet) BitArray() *bits.BitArray {
  300. if voteSet == nil {
  301. return nil
  302. }
  303. voteSet.mtx.Lock()
  304. defer voteSet.mtx.Unlock()
  305. return voteSet.votesBitArray.Copy()
  306. }
  307. func (voteSet *VoteSet) BitArrayByBlockID(blockID BlockID) *bits.BitArray {
  308. if voteSet == nil {
  309. return nil
  310. }
  311. voteSet.mtx.Lock()
  312. defer voteSet.mtx.Unlock()
  313. votesByBlock, ok := voteSet.votesByBlock[blockID.Key()]
  314. if ok {
  315. return votesByBlock.bitArray.Copy()
  316. }
  317. return nil
  318. }
  319. // NOTE: if validator has conflicting votes, returns "canonical" vote
  320. // Implements VoteSetReader.
  321. func (voteSet *VoteSet) GetByIndex(valIndex int) *Vote {
  322. if voteSet == nil {
  323. return nil
  324. }
  325. voteSet.mtx.Lock()
  326. defer voteSet.mtx.Unlock()
  327. return voteSet.votes[valIndex]
  328. }
  329. func (voteSet *VoteSet) GetByAddress(address []byte) *Vote {
  330. if voteSet == nil {
  331. return nil
  332. }
  333. voteSet.mtx.Lock()
  334. defer voteSet.mtx.Unlock()
  335. valIndex, val := voteSet.valSet.GetByAddress(address)
  336. if val == nil {
  337. panic("GetByAddress(address) returned nil")
  338. }
  339. return voteSet.votes[valIndex]
  340. }
  341. func (voteSet *VoteSet) HasTwoThirdsMajority() bool {
  342. if voteSet == nil {
  343. return false
  344. }
  345. voteSet.mtx.Lock()
  346. defer voteSet.mtx.Unlock()
  347. return voteSet.maj23 != nil
  348. }
  349. // Implements VoteSetReader.
  350. func (voteSet *VoteSet) IsCommit() bool {
  351. if voteSet == nil {
  352. return false
  353. }
  354. if voteSet.signedMsgType != PrecommitType {
  355. return false
  356. }
  357. voteSet.mtx.Lock()
  358. defer voteSet.mtx.Unlock()
  359. return voteSet.maj23 != nil
  360. }
  361. func (voteSet *VoteSet) HasTwoThirdsAny() bool {
  362. if voteSet == nil {
  363. return false
  364. }
  365. voteSet.mtx.Lock()
  366. defer voteSet.mtx.Unlock()
  367. return voteSet.sum > voteSet.valSet.TotalVotingPower()*2/3
  368. }
  369. func (voteSet *VoteSet) HasAll() bool {
  370. voteSet.mtx.Lock()
  371. defer voteSet.mtx.Unlock()
  372. return voteSet.sum == voteSet.valSet.TotalVotingPower()
  373. }
  374. // If there was a +2/3 majority for blockID, return blockID and true.
  375. // Else, return the empty BlockID{} and false.
  376. func (voteSet *VoteSet) TwoThirdsMajority() (blockID BlockID, ok bool) {
  377. if voteSet == nil {
  378. return BlockID{}, false
  379. }
  380. voteSet.mtx.Lock()
  381. defer voteSet.mtx.Unlock()
  382. if voteSet.maj23 != nil {
  383. return *voteSet.maj23, true
  384. }
  385. return BlockID{}, false
  386. }
  387. //--------------------------------------------------------------------------------
  388. // Strings and JSON
  389. func (voteSet *VoteSet) String() string {
  390. if voteSet == nil {
  391. return "nil-VoteSet"
  392. }
  393. return voteSet.StringIndented("")
  394. }
  395. func (voteSet *VoteSet) StringIndented(indent string) string {
  396. voteSet.mtx.Lock()
  397. defer voteSet.mtx.Unlock()
  398. voteStrings := make([]string, len(voteSet.votes))
  399. for i, vote := range voteSet.votes {
  400. if vote == nil {
  401. voteStrings[i] = nilVoteStr
  402. } else {
  403. voteStrings[i] = vote.String()
  404. }
  405. }
  406. return fmt.Sprintf(`VoteSet{
  407. %s H:%v R:%v T:%v
  408. %s %v
  409. %s %v
  410. %s %v
  411. %s}`,
  412. indent, voteSet.height, voteSet.round, voteSet.signedMsgType,
  413. indent, strings.Join(voteStrings, "\n"+indent+" "),
  414. indent, voteSet.votesBitArray,
  415. indent, voteSet.peerMaj23s,
  416. indent)
  417. }
  418. // Marshal the VoteSet to JSON. Same as String(), just in JSON,
  419. // and without the height/round/signedMsgType (since its already included in the votes).
  420. func (voteSet *VoteSet) MarshalJSON() ([]byte, error) {
  421. voteSet.mtx.Lock()
  422. defer voteSet.mtx.Unlock()
  423. return cdc.MarshalJSON(VoteSetJSON{
  424. voteSet.voteStrings(),
  425. voteSet.bitArrayString(),
  426. voteSet.peerMaj23s,
  427. })
  428. }
  429. // More human readable JSON of the vote set
  430. // NOTE: insufficient for unmarshalling from (compressed votes)
  431. // TODO: make the peerMaj23s nicer to read (eg just the block hash)
  432. type VoteSetJSON struct {
  433. Votes []string `json:"votes"`
  434. VotesBitArray string `json:"votes_bit_array"`
  435. PeerMaj23s map[P2PID]BlockID `json:"peer_maj_23s"`
  436. }
  437. // Return the bit-array of votes including
  438. // the fraction of power that has voted like:
  439. // "BA{29:xx__x__x_x___x__x_______xxx__} 856/1304 = 0.66"
  440. func (voteSet *VoteSet) BitArrayString() string {
  441. voteSet.mtx.Lock()
  442. defer voteSet.mtx.Unlock()
  443. return voteSet.bitArrayString()
  444. }
  445. func (voteSet *VoteSet) bitArrayString() string {
  446. bAString := voteSet.votesBitArray.String()
  447. voted, total, fracVoted := voteSet.sumTotalFrac()
  448. return fmt.Sprintf("%s %d/%d = %.2f", bAString, voted, total, fracVoted)
  449. }
  450. // Returns a list of votes compressed to more readable strings.
  451. func (voteSet *VoteSet) VoteStrings() []string {
  452. voteSet.mtx.Lock()
  453. defer voteSet.mtx.Unlock()
  454. return voteSet.voteStrings()
  455. }
  456. func (voteSet *VoteSet) voteStrings() []string {
  457. voteStrings := make([]string, len(voteSet.votes))
  458. for i, vote := range voteSet.votes {
  459. if vote == nil {
  460. voteStrings[i] = nilVoteStr
  461. } else {
  462. voteStrings[i] = vote.String()
  463. }
  464. }
  465. return voteStrings
  466. }
  467. func (voteSet *VoteSet) StringShort() string {
  468. if voteSet == nil {
  469. return "nil-VoteSet"
  470. }
  471. voteSet.mtx.Lock()
  472. defer voteSet.mtx.Unlock()
  473. _, _, frac := voteSet.sumTotalFrac()
  474. return fmt.Sprintf(`VoteSet{H:%v R:%v T:%v +2/3:%v(%v) %v %v}`,
  475. voteSet.height, voteSet.round, voteSet.signedMsgType, voteSet.maj23, frac, voteSet.votesBitArray, voteSet.peerMaj23s)
  476. }
  477. // return the power voted, the total, and the fraction
  478. func (voteSet *VoteSet) sumTotalFrac() (int64, int64, float64) {
  479. voted, total := voteSet.sum, voteSet.valSet.TotalVotingPower()
  480. fracVoted := float64(voted) / float64(total)
  481. return voted, total, fracVoted
  482. }
  483. //--------------------------------------------------------------------------------
  484. // Commit
  485. // MakeCommit constructs a Commit from the VoteSet.
  486. // Panics if the vote type is not PrecommitType or if
  487. // there's no +2/3 votes for a single block.
  488. func (voteSet *VoteSet) MakeCommit() *Commit {
  489. if voteSet.signedMsgType != PrecommitType {
  490. panic("Cannot MakeCommit() unless VoteSet.Type is PrecommitType")
  491. }
  492. voteSet.mtx.Lock()
  493. defer voteSet.mtx.Unlock()
  494. // Make sure we have a 2/3 majority
  495. if voteSet.maj23 == nil {
  496. panic("Cannot MakeCommit() unless a blockhash has +2/3")
  497. }
  498. // For every validator, get the precommit
  499. commitSigs := make([]CommitSig, len(voteSet.votes))
  500. for i, v := range voteSet.votes {
  501. commitSigs[i] = v.CommitSig()
  502. }
  503. return NewCommit(voteSet.GetHeight(), voteSet.GetRound(), *voteSet.maj23, commitSigs)
  504. }
  505. //--------------------------------------------------------------------------------
  506. /*
  507. Votes for a particular block
  508. There are two ways a *blockVotes gets created for a blockKey.
  509. 1. first (non-conflicting) vote of a validator w/ blockKey (peerMaj23=false)
  510. 2. A peer claims to have a 2/3 majority w/ blockKey (peerMaj23=true)
  511. */
  512. type blockVotes struct {
  513. peerMaj23 bool // peer claims to have maj23
  514. bitArray *bits.BitArray // valIndex -> hasVote?
  515. votes []*Vote // valIndex -> *Vote
  516. sum int64 // vote sum
  517. }
  518. func newBlockVotes(peerMaj23 bool, numValidators int) *blockVotes {
  519. return &blockVotes{
  520. peerMaj23: peerMaj23,
  521. bitArray: bits.NewBitArray(numValidators),
  522. votes: make([]*Vote, numValidators),
  523. sum: 0,
  524. }
  525. }
  526. func (vs *blockVotes) addVerifiedVote(vote *Vote, votingPower int64) {
  527. valIndex := vote.ValidatorIndex
  528. if existing := vs.votes[valIndex]; existing == nil {
  529. vs.bitArray.SetIndex(valIndex, true)
  530. vs.votes[valIndex] = vote
  531. vs.sum += votingPower
  532. }
  533. }
  534. func (vs *blockVotes) getByIndex(index int) *Vote {
  535. if vs == nil {
  536. return nil
  537. }
  538. return vs.votes[index]
  539. }
  540. //--------------------------------------------------------------------------------
  541. // Common interface between *consensus.VoteSet and types.Commit
  542. type VoteSetReader interface {
  543. GetHeight() int64
  544. GetRound() int
  545. Type() byte
  546. Size() int
  547. BitArray() *bits.BitArray
  548. GetByIndex(int) *Vote
  549. IsCommit() bool
  550. }