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.

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