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.

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