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.

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