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
3.1 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
  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 `json:"round"`
  16. Signature account.SignatureEd25519 `json:"signature"`
  17. }
  18. // Proof of lock.
  19. // +2/3 of validators' prevotes for a given blockhash (or nil)
  20. type POL struct {
  21. Height uint `json:"height"`
  22. Round uint `json:"round"`
  23. BlockHash []byte `json:"block_hash"` // Could be nil, which makes this a proof of unlock.
  24. BlockParts types.PartSetHeader `json:"block_parts"` // When BlockHash is nil, this is zero.
  25. Votes []POLVoteSignature `json:"votes"` // 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 fmt.Errorf("Invalid POL votes count: Expected %v, got %v",
  31. valSet.Size(), len(pol.Votes))
  32. }
  33. talliedVotingPower := uint64(0)
  34. prevoteDoc := account.SignBytes(config.GetString("chain_id"), &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(config.GetString("chain_id"), &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 fmt.Errorf("Invalid commit round %v for POL %v", vote.Round, pol)
  56. }
  57. // Validate
  58. if _, seen := seenValidators[string(val.Address)]; seen {
  59. return fmt.Errorf("Duplicate validator for vote %v for POL %v", vote, pol)
  60. }
  61. if !val.PubKey.VerifyBytes(voteDoc, vote.Signature) {
  62. return fmt.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 fmt.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. }