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.

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