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.

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