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.

698 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
3 years ago
8 years ago
10 years ago
10 years ago
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. "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. // 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 sync.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. func (voteSet *VoteSet) GetVotes() []*Vote {
  198. if voteSet == nil {
  199. return nil
  200. }
  201. return voteSet.votes
  202. }
  203. // Assumes signature is valid.
  204. // If conflicting vote exists, returns it.
  205. func (voteSet *VoteSet) addVerifiedVote(
  206. vote *Vote,
  207. blockKey string,
  208. votingPower int64,
  209. ) (added bool, conflicting *Vote) {
  210. valIndex := vote.ValidatorIndex
  211. // Already exists in voteSet.votes?
  212. if existing := voteSet.votes[valIndex]; existing != nil {
  213. if existing.BlockID.Equals(vote.BlockID) {
  214. panic("addVerifiedVote does not expect duplicate votes")
  215. } else {
  216. conflicting = existing
  217. }
  218. // Replace vote if blockKey matches voteSet.maj23.
  219. if voteSet.maj23 != nil && voteSet.maj23.Key() == blockKey {
  220. voteSet.votes[valIndex] = vote
  221. voteSet.votesBitArray.SetIndex(int(valIndex), true)
  222. }
  223. // Otherwise don't add it to voteSet.votes
  224. } else {
  225. // Add to voteSet.votes and incr .sum
  226. voteSet.votes[valIndex] = vote
  227. voteSet.votesBitArray.SetIndex(int(valIndex), true)
  228. voteSet.sum += votingPower
  229. }
  230. votesByBlock, ok := voteSet.votesByBlock[blockKey]
  231. if ok {
  232. if conflicting != nil && !votesByBlock.peerMaj23 {
  233. // There's a conflict and no peer claims that this block is special.
  234. return false, conflicting
  235. }
  236. // We'll add the vote in a bit.
  237. } else {
  238. // .votesByBlock doesn't exist...
  239. if conflicting != nil {
  240. // ... and there's a conflicting vote.
  241. // We're not even tracking this blockKey, so just forget it.
  242. return false, conflicting
  243. }
  244. // ... and there's no conflicting vote.
  245. // Start tracking this blockKey
  246. votesByBlock = newBlockVotes(false, voteSet.valSet.Size())
  247. voteSet.votesByBlock[blockKey] = votesByBlock
  248. // We'll add the vote in a bit.
  249. }
  250. // Before adding to votesByBlock, see if we'll exceed quorum
  251. origSum := votesByBlock.sum
  252. quorum := voteSet.valSet.TotalVotingPower()*2/3 + 1
  253. // Add vote to votesByBlock
  254. votesByBlock.addVerifiedVote(vote, votingPower)
  255. // If we just crossed the quorum threshold and have 2/3 majority...
  256. if origSum < quorum && quorum <= votesByBlock.sum {
  257. // Only consider the first quorum reached
  258. if voteSet.maj23 == nil {
  259. maj23BlockID := vote.BlockID
  260. voteSet.maj23 = &maj23BlockID
  261. // And also copy votes over to voteSet.votes
  262. for i, vote := range votesByBlock.votes {
  263. if vote != nil {
  264. voteSet.votes[i] = vote
  265. }
  266. }
  267. }
  268. }
  269. return true, conflicting
  270. }
  271. // If a peer claims that it has 2/3 majority for given blockKey, call this.
  272. // NOTE: if there are too many peers, or too much peer churn,
  273. // this can cause memory issues.
  274. // TODO: implement ability to remove peers too
  275. // NOTE: VoteSet must not be nil
  276. func (voteSet *VoteSet) SetPeerMaj23(peerID P2PID, blockID BlockID) error {
  277. if voteSet == nil {
  278. panic("SetPeerMaj23() on nil VoteSet")
  279. }
  280. voteSet.mtx.Lock()
  281. defer voteSet.mtx.Unlock()
  282. blockKey := blockID.Key()
  283. // Make sure peer hasn't already told us something.
  284. if existing, ok := voteSet.peerMaj23s[peerID]; ok {
  285. if existing.Equals(blockID) {
  286. return nil // Nothing to do
  287. }
  288. return fmt.Errorf("setPeerMaj23: Received conflicting blockID from peer %v. Got %v, expected %v",
  289. peerID, blockID, existing)
  290. }
  291. voteSet.peerMaj23s[peerID] = blockID
  292. // Create .votesByBlock entry if needed.
  293. votesByBlock, ok := voteSet.votesByBlock[blockKey]
  294. if ok {
  295. if votesByBlock.peerMaj23 {
  296. return nil // Nothing to do
  297. }
  298. votesByBlock.peerMaj23 = true
  299. // No need to copy votes, already there.
  300. } else {
  301. votesByBlock = newBlockVotes(true, voteSet.valSet.Size())
  302. voteSet.votesByBlock[blockKey] = votesByBlock
  303. // No need to copy votes, no votes to copy over.
  304. }
  305. return nil
  306. }
  307. // Implements VoteSetReader.
  308. func (voteSet *VoteSet) BitArray() *bits.BitArray {
  309. if voteSet == nil {
  310. return nil
  311. }
  312. voteSet.mtx.Lock()
  313. defer voteSet.mtx.Unlock()
  314. return voteSet.votesBitArray.Copy()
  315. }
  316. func (voteSet *VoteSet) BitArrayByBlockID(blockID BlockID) *bits.BitArray {
  317. if voteSet == nil {
  318. return nil
  319. }
  320. voteSet.mtx.Lock()
  321. defer voteSet.mtx.Unlock()
  322. votesByBlock, ok := voteSet.votesByBlock[blockID.Key()]
  323. if ok {
  324. return votesByBlock.bitArray.Copy()
  325. }
  326. return nil
  327. }
  328. // NOTE: if validator has conflicting votes, returns "canonical" vote
  329. // Implements VoteSetReader.
  330. func (voteSet *VoteSet) GetByIndex(valIndex int32) *Vote {
  331. if voteSet == nil {
  332. return nil
  333. }
  334. voteSet.mtx.Lock()
  335. defer voteSet.mtx.Unlock()
  336. if int(valIndex) >= len(voteSet.votes) {
  337. return nil
  338. }
  339. return voteSet.votes[valIndex]
  340. }
  341. // List returns a copy of the list of votes stored by the VoteSet.
  342. func (voteSet *VoteSet) List() []Vote {
  343. if voteSet == nil || voteSet.votes == nil {
  344. return nil
  345. }
  346. votes := make([]Vote, 0, len(voteSet.votes))
  347. for i := range voteSet.votes {
  348. if voteSet.votes[i] != nil {
  349. votes = append(votes, *voteSet.votes[i])
  350. }
  351. }
  352. return votes
  353. }
  354. func (voteSet *VoteSet) GetByAddress(address []byte) *Vote {
  355. if voteSet == nil {
  356. return nil
  357. }
  358. voteSet.mtx.Lock()
  359. defer voteSet.mtx.Unlock()
  360. valIndex, val := voteSet.valSet.GetByAddress(address)
  361. if val == nil {
  362. panic("GetByAddress(address) returned nil")
  363. }
  364. return voteSet.votes[valIndex]
  365. }
  366. func (voteSet *VoteSet) HasTwoThirdsMajority() bool {
  367. if voteSet == nil {
  368. return false
  369. }
  370. voteSet.mtx.Lock()
  371. defer voteSet.mtx.Unlock()
  372. return voteSet.maj23 != nil
  373. }
  374. // Implements VoteSetReader.
  375. func (voteSet *VoteSet) IsCommit() bool {
  376. if voteSet == nil {
  377. return false
  378. }
  379. if voteSet.signedMsgType != tmproto.PrecommitType {
  380. return false
  381. }
  382. voteSet.mtx.Lock()
  383. defer voteSet.mtx.Unlock()
  384. return voteSet.maj23 != nil
  385. }
  386. func (voteSet *VoteSet) HasTwoThirdsAny() bool {
  387. if voteSet == nil {
  388. return false
  389. }
  390. voteSet.mtx.Lock()
  391. defer voteSet.mtx.Unlock()
  392. return voteSet.sum > voteSet.valSet.TotalVotingPower()*2/3
  393. }
  394. func (voteSet *VoteSet) HasAll() bool {
  395. if voteSet == nil {
  396. return false
  397. }
  398. voteSet.mtx.Lock()
  399. defer voteSet.mtx.Unlock()
  400. return voteSet.sum == voteSet.valSet.TotalVotingPower()
  401. }
  402. // If there was a +2/3 majority for blockID, return blockID and true.
  403. // Else, return the empty BlockID{} and false.
  404. func (voteSet *VoteSet) TwoThirdsMajority() (blockID BlockID, ok bool) {
  405. if voteSet == nil {
  406. return BlockID{}, false
  407. }
  408. voteSet.mtx.Lock()
  409. defer voteSet.mtx.Unlock()
  410. if voteSet.maj23 != nil {
  411. return *voteSet.maj23, true
  412. }
  413. return BlockID{}, false
  414. }
  415. //--------------------------------------------------------------------------------
  416. // Strings and JSON
  417. const nilVoteSetString = "nil-VoteSet"
  418. // String returns a string representation of VoteSet.
  419. //
  420. // See StringIndented.
  421. func (voteSet *VoteSet) String() string {
  422. if voteSet == nil {
  423. return nilVoteSetString
  424. }
  425. return voteSet.StringIndented("")
  426. }
  427. // StringIndented returns an indented String.
  428. //
  429. // Height Round Type
  430. // Votes
  431. // Votes bit array
  432. // 2/3+ majority
  433. //
  434. // See Vote#String.
  435. func (voteSet *VoteSet) StringIndented(indent string) string {
  436. voteSet.mtx.Lock()
  437. defer voteSet.mtx.Unlock()
  438. voteStrings := make([]string, len(voteSet.votes))
  439. for i, vote := range voteSet.votes {
  440. if vote == nil {
  441. voteStrings[i] = nilVoteStr
  442. } else {
  443. voteStrings[i] = vote.String()
  444. }
  445. }
  446. return fmt.Sprintf(`VoteSet{
  447. %s H:%v R:%v T:%v
  448. %s %v
  449. %s %v
  450. %s %v
  451. %s}`,
  452. indent, voteSet.height, voteSet.round, voteSet.signedMsgType,
  453. indent, strings.Join(voteStrings, "\n"+indent+" "),
  454. indent, voteSet.votesBitArray,
  455. indent, voteSet.peerMaj23s,
  456. indent)
  457. }
  458. // Marshal the VoteSet to JSON. Same as String(), just in JSON,
  459. // and without the height/round/signedMsgType (since its already included in the votes).
  460. func (voteSet *VoteSet) MarshalJSON() ([]byte, error) {
  461. voteSet.mtx.Lock()
  462. defer voteSet.mtx.Unlock()
  463. return json.Marshal(VoteSetJSON{
  464. voteSet.voteStrings(),
  465. voteSet.bitArrayString(),
  466. voteSet.peerMaj23s,
  467. })
  468. }
  469. // More human readable JSON of the vote set
  470. // NOTE: insufficient for unmarshaling from (compressed votes)
  471. // TODO: make the peerMaj23s nicer to read (eg just the block hash)
  472. type VoteSetJSON struct {
  473. Votes []string `json:"votes"`
  474. VotesBitArray string `json:"votes_bit_array"`
  475. PeerMaj23s map[P2PID]BlockID `json:"peer_maj_23s"`
  476. }
  477. // Return the bit-array of votes including
  478. // the fraction of power that has voted like:
  479. // "BA{29:xx__x__x_x___x__x_______xxx__} 856/1304 = 0.66"
  480. func (voteSet *VoteSet) BitArrayString() string {
  481. voteSet.mtx.Lock()
  482. defer voteSet.mtx.Unlock()
  483. return voteSet.bitArrayString()
  484. }
  485. func (voteSet *VoteSet) bitArrayString() string {
  486. bAString := voteSet.votesBitArray.String()
  487. voted, total, fracVoted := voteSet.sumTotalFrac()
  488. return fmt.Sprintf("%s %d/%d = %.2f", bAString, voted, total, fracVoted)
  489. }
  490. // Returns a list of votes compressed to more readable strings.
  491. func (voteSet *VoteSet) VoteStrings() []string {
  492. voteSet.mtx.Lock()
  493. defer voteSet.mtx.Unlock()
  494. return voteSet.voteStrings()
  495. }
  496. func (voteSet *VoteSet) voteStrings() []string {
  497. voteStrings := make([]string, len(voteSet.votes))
  498. for i, vote := range voteSet.votes {
  499. if vote == nil {
  500. voteStrings[i] = nilVoteStr
  501. } else {
  502. voteStrings[i] = vote.String()
  503. }
  504. }
  505. return voteStrings
  506. }
  507. // StringShort returns a short representation of VoteSet.
  508. //
  509. // 1. height
  510. // 2. round
  511. // 3. signed msg type
  512. // 4. first 2/3+ majority
  513. // 5. fraction of voted power
  514. // 6. votes bit array
  515. // 7. 2/3+ majority for each peer
  516. func (voteSet *VoteSet) StringShort() string {
  517. if voteSet == nil {
  518. return nilVoteSetString
  519. }
  520. voteSet.mtx.Lock()
  521. defer voteSet.mtx.Unlock()
  522. _, _, frac := voteSet.sumTotalFrac()
  523. return fmt.Sprintf(`VoteSet{H:%v R:%v T:%v +2/3:%v(%v) %v %v}`,
  524. voteSet.height, voteSet.round, voteSet.signedMsgType, voteSet.maj23, frac, voteSet.votesBitArray, voteSet.peerMaj23s)
  525. }
  526. // LogString produces a logging suitable string representation of the
  527. // vote set.
  528. func (voteSet *VoteSet) LogString() string {
  529. if voteSet == nil {
  530. return nilVoteSetString
  531. }
  532. voteSet.mtx.Lock()
  533. defer voteSet.mtx.Unlock()
  534. voted, total, frac := voteSet.sumTotalFrac()
  535. return fmt.Sprintf("Votes:%d/%d(%.3f)", voted, total, frac)
  536. }
  537. // return the power voted, the total, and the fraction
  538. func (voteSet *VoteSet) sumTotalFrac() (int64, int64, float64) {
  539. voted, total := voteSet.sum, voteSet.valSet.TotalVotingPower()
  540. fracVoted := float64(voted) / float64(total)
  541. return voted, total, fracVoted
  542. }
  543. //--------------------------------------------------------------------------------
  544. // Commit
  545. // MakeCommit constructs a Commit from the VoteSet. It only includes precommits
  546. // for the block, which has 2/3+ majority, and nil.
  547. //
  548. // Panics if the vote type is not PrecommitType or if there's no +2/3 votes for
  549. // a single block.
  550. func (voteSet *VoteSet) MakeCommit() *Commit {
  551. if voteSet.signedMsgType != tmproto.PrecommitType {
  552. panic("Cannot MakeCommit() unless VoteSet.Type is PrecommitType")
  553. }
  554. voteSet.mtx.Lock()
  555. defer voteSet.mtx.Unlock()
  556. // Make sure we have a 2/3 majority
  557. if voteSet.maj23 == nil {
  558. panic("Cannot MakeCommit() unless a blockhash has +2/3")
  559. }
  560. // For every validator, get the precommit
  561. commitSigs := make([]CommitSig, len(voteSet.votes))
  562. for i, v := range voteSet.votes {
  563. commitSig := v.CommitSig()
  564. // if block ID exists but doesn't match, exclude sig
  565. if commitSig.ForBlock() && !v.BlockID.Equals(*voteSet.maj23) {
  566. commitSig = NewCommitSigAbsent()
  567. }
  568. commitSigs[i] = commitSig
  569. }
  570. return NewCommit(voteSet.GetHeight(), voteSet.GetRound(), *voteSet.maj23, commitSigs)
  571. }
  572. //--------------------------------------------------------------------------------
  573. /*
  574. Votes for a particular block
  575. There are two ways a *blockVotes gets created for a blockKey.
  576. 1. first (non-conflicting) vote of a validator w/ blockKey (peerMaj23=false)
  577. 2. A peer claims to have a 2/3 majority w/ blockKey (peerMaj23=true)
  578. */
  579. type blockVotes struct {
  580. peerMaj23 bool // peer claims to have maj23
  581. bitArray *bits.BitArray // valIndex -> hasVote?
  582. votes []*Vote // valIndex -> *Vote
  583. sum int64 // vote sum
  584. }
  585. func newBlockVotes(peerMaj23 bool, numValidators int) *blockVotes {
  586. return &blockVotes{
  587. peerMaj23: peerMaj23,
  588. bitArray: bits.NewBitArray(numValidators),
  589. votes: make([]*Vote, numValidators),
  590. sum: 0,
  591. }
  592. }
  593. func (vs *blockVotes) addVerifiedVote(vote *Vote, votingPower int64) {
  594. valIndex := vote.ValidatorIndex
  595. if existing := vs.votes[valIndex]; existing == nil {
  596. vs.bitArray.SetIndex(int(valIndex), true)
  597. vs.votes[valIndex] = vote
  598. vs.sum += votingPower
  599. }
  600. }
  601. func (vs *blockVotes) getByIndex(index int32) *Vote {
  602. if vs == nil {
  603. return nil
  604. }
  605. return vs.votes[index]
  606. }
  607. //--------------------------------------------------------------------------------
  608. // Common interface between *consensus.VoteSet and types.Commit
  609. type VoteSetReader interface {
  610. GetHeight() int64
  611. GetRound() int32
  612. Type() byte
  613. Size() int
  614. BitArray() *bits.BitArray
  615. GetByIndex(int32) *Vote
  616. IsCommit() bool
  617. }