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.

98 lines
2.9 KiB

10 years ago
  1. package consensus
  2. import (
  3. "io"
  4. . "github.com/tendermint/tendermint/binary"
  5. . "github.com/tendermint/tendermint/blocks"
  6. . "github.com/tendermint/tendermint/common"
  7. . "github.com/tendermint/tendermint/state"
  8. )
  9. // Proof of lock.
  10. // +2/3 of validators' (bare) votes for a given blockhash (or nil)
  11. type POL struct {
  12. Height uint32
  13. Round uint16
  14. BlockHash []byte // Could be nil, which makes this a proof of unlock.
  15. Votes []Signature // Vote signatures for height/round/hash
  16. Commits []Signature // Commit signatures for height/hash
  17. CommitRounds []uint16 // Rounds of the commits, less than POL.Round.
  18. }
  19. func ReadPOL(r io.Reader, n *int64, err *error) *POL {
  20. return &POL{
  21. Height: ReadUInt32(r, n, err),
  22. Round: ReadUInt16(r, n, err),
  23. BlockHash: ReadByteSlice(r, n, err),
  24. Votes: ReadSignatures(r, n, err),
  25. Commits: ReadSignatures(r, n, err),
  26. CommitRounds: ReadUInt16s(r, n, err),
  27. }
  28. }
  29. func (pol *POL) WriteTo(w io.Writer) (n int64, err error) {
  30. WriteUInt32(w, pol.Height, &n, &err)
  31. WriteUInt16(w, pol.Round, &n, &err)
  32. WriteByteSlice(w, pol.BlockHash, &n, &err)
  33. WriteSignatures(w, pol.Votes, &n, &err)
  34. WriteSignatures(w, pol.Commits, &n, &err)
  35. WriteUInt16s(w, pol.CommitRounds, &n, &err)
  36. return
  37. }
  38. // Returns whether +2/3 have voted/committed for BlockHash.
  39. func (pol *POL) Verify(vset *ValidatorSet) error {
  40. talliedVotingPower := uint64(0)
  41. voteDoc := GenVoteDocument(VoteTypeBare, pol.Height, pol.Round, pol.BlockHash)
  42. seenValidators := map[uint64]struct{}{}
  43. for _, sig := range pol.Votes {
  44. // Validate
  45. if _, seen := seenValidators[sig.SignerId]; seen {
  46. return Errorf("Duplicate validator for vote %v for POL %v", sig, pol)
  47. }
  48. validator := vset.GetById(sig.SignerId)
  49. if validator == nil {
  50. return Errorf("Invalid validator for vote %v for POL %v", sig, pol)
  51. }
  52. if !validator.Verify(voteDoc, sig) {
  53. return Errorf("Invalid signature for vote %v for POL %v", sig, pol)
  54. }
  55. // Tally
  56. seenValidators[validator.Id] = struct{}{}
  57. talliedVotingPower += validator.VotingPower
  58. }
  59. for i, sig := range pol.Commits {
  60. round := pol.CommitRounds[i]
  61. // Validate
  62. if _, seen := seenValidators[sig.SignerId]; seen {
  63. return Errorf("Duplicate validator for commit %v for POL %v", sig, pol)
  64. }
  65. validator := vset.GetById(sig.SignerId)
  66. if validator == nil {
  67. return Errorf("Invalid validator for commit %v for POL %v", sig, pol)
  68. }
  69. commitDoc := GenVoteDocument(VoteTypeCommit, pol.Height, round, pol.BlockHash) // TODO cache
  70. if !validator.Verify(commitDoc, sig) {
  71. return Errorf("Invalid signature for commit %v for POL %v", sig, pol)
  72. }
  73. // Tally
  74. seenValidators[validator.Id] = struct{}{}
  75. talliedVotingPower += validator.VotingPower
  76. }
  77. if talliedVotingPower > vset.TotalVotingPower()*2/3 {
  78. return nil
  79. } else {
  80. return Errorf("Invalid POL, insufficient voting power %v, needed %v",
  81. talliedVotingPower, (vset.TotalVotingPower()*2/3 + 1))
  82. }
  83. }