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.

96 lines
2.7 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. package consensus
  2. import (
  3. "fmt"
  4. . "github.com/tendermint/tendermint/account"
  5. . "github.com/tendermint/tendermint/block"
  6. . "github.com/tendermint/tendermint/common"
  7. "github.com/tendermint/tendermint/state"
  8. )
  9. // Each signature of a POL (proof-of-lock, see whitepaper) is
  10. // either a prevote or a commit.
  11. // Commits require an additional round which is strictly less than
  12. // the POL round. Prevote rounds are equal to the POL round.
  13. type POLVoteSignature struct {
  14. Round uint
  15. Signature SignatureEd25519
  16. }
  17. // Proof of lock.
  18. // +2/3 of validators' prevotes for a given blockhash (or nil)
  19. type POL struct {
  20. Height uint
  21. Round uint
  22. BlockHash []byte // Could be nil, which makes this a proof of unlock.
  23. BlockParts PartSetHeader // When BlockHash is nil, this is zero.
  24. Votes []POLVoteSignature // Prevote and commit signatures in ValidatorSet order.
  25. }
  26. // Returns whether +2/3 have prevoted/committed for BlockHash.
  27. func (pol *POL) Verify(valSet *state.ValidatorSet) error {
  28. if uint(len(pol.Votes)) != valSet.Size() {
  29. return Errorf("Invalid POL votes count: Expected %v, got %v",
  30. valSet.Size(), len(pol.Votes))
  31. }
  32. talliedVotingPower := uint64(0)
  33. prevoteDoc := SignBytes(&Vote{
  34. Height: pol.Height, Round: pol.Round, Type: VoteTypePrevote,
  35. BlockHash: pol.BlockHash,
  36. BlockParts: pol.BlockParts,
  37. })
  38. seenValidators := map[string]struct{}{}
  39. for idx, vote := range pol.Votes {
  40. // vote may be zero, in which case skip.
  41. if vote.Signature.IsZero() {
  42. continue
  43. }
  44. voteDoc := prevoteDoc
  45. _, val := valSet.GetByIndex(uint(idx))
  46. // Commit vote?
  47. if vote.Round < pol.Round {
  48. voteDoc = SignBytes(&Vote{
  49. Height: pol.Height, Round: vote.Round, Type: VoteTypeCommit,
  50. BlockHash: pol.BlockHash,
  51. BlockParts: pol.BlockParts,
  52. })
  53. } else if vote.Round > pol.Round {
  54. return Errorf("Invalid commit round %v for POL %v", vote.Round, pol)
  55. }
  56. // Validate
  57. if _, seen := seenValidators[string(val.Address)]; seen {
  58. return Errorf("Duplicate validator for vote %v for POL %v", vote, pol)
  59. }
  60. if !val.PubKey.VerifyBytes(voteDoc, vote.Signature) {
  61. return Errorf("Invalid signature for vote %v for POL %v", vote, pol)
  62. }
  63. // Tally
  64. seenValidators[string(val.Address)] = struct{}{}
  65. talliedVotingPower += val.VotingPower
  66. }
  67. if talliedVotingPower > valSet.TotalVotingPower()*2/3 {
  68. return nil
  69. } else {
  70. return Errorf("Invalid POL, insufficient voting power %v, needed %v",
  71. talliedVotingPower, (valSet.TotalVotingPower()*2/3 + 1))
  72. }
  73. }
  74. func (pol *POL) Description() string {
  75. if pol == nil {
  76. return "nil-POL"
  77. } else {
  78. return fmt.Sprintf("POL{H:%v R:%v BH:%X}", pol.Height, pol.Round,
  79. Fingerprint(pol.BlockHash), pol.BlockParts)
  80. }
  81. }