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.

121 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
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. BlockParts PartSetHeader // When BlockHash is nil, this is zero.
  17. Votes []Signature // Vote signatures for height/round/hash
  18. Commits []RoundSignature // Commit signatures for height/hash
  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. BlockParts: ReadPartSetHeader(r, n, err),
  26. Votes: ReadSignatures(r, n, err),
  27. Commits: ReadRoundSignatures(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. WriteBinary(w, pol.BlockParts, &n, &err)
  35. WriteSignatures(w, pol.Votes, &n, &err)
  36. WriteRoundSignatures(w, pol.Commits, &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{
  43. Height: pol.Height, Round: pol.Round, Type: VoteTypePrevote,
  44. BlockHash: pol.BlockHash,
  45. BlockParts: pol.BlockParts,
  46. })
  47. seenValidators := map[uint64]struct{}{}
  48. for _, sig := range pol.Votes {
  49. // Validate
  50. if _, seen := seenValidators[sig.SignerId]; seen {
  51. return Errorf("Duplicate validator for vote %v for POL %v", sig, pol)
  52. }
  53. _, val := vset.GetById(sig.SignerId)
  54. if val == nil {
  55. return Errorf("Invalid validator for vote %v for POL %v", sig, pol)
  56. }
  57. if !val.VerifyBytes(voteDoc, sig) {
  58. return Errorf("Invalid signature for vote %v for POL %v", sig, pol)
  59. }
  60. // Tally
  61. seenValidators[val.Id] = struct{}{}
  62. talliedVotingPower += val.VotingPower
  63. }
  64. for _, rsig := range pol.Commits {
  65. round := rsig.Round
  66. sig := rsig.Signature
  67. // Validate
  68. if _, seen := seenValidators[sig.SignerId]; seen {
  69. return Errorf("Duplicate validator for commit %v for POL %v", sig, pol)
  70. }
  71. _, val := vset.GetById(sig.SignerId)
  72. if val == nil {
  73. return Errorf("Invalid validator for commit %v for POL %v", sig, pol)
  74. }
  75. if round >= pol.Round {
  76. return Errorf("Invalid commit round %v for POL %v", round, pol)
  77. }
  78. commitDoc := BinaryBytes(&Vote{
  79. Height: pol.Height, Round: round, Type: VoteTypeCommit,
  80. BlockHash: pol.BlockHash,
  81. BlockParts: pol.BlockParts,
  82. })
  83. if !val.VerifyBytes(commitDoc, sig) {
  84. return Errorf("Invalid signature for commit %v for POL %v", sig, pol)
  85. }
  86. // Tally
  87. seenValidators[val.Id] = struct{}{}
  88. talliedVotingPower += val.VotingPower
  89. }
  90. if talliedVotingPower > vset.TotalVotingPower()*2/3 {
  91. return nil
  92. } else {
  93. return Errorf("Invalid POL, insufficient voting power %v, needed %v",
  94. talliedVotingPower, (vset.TotalVotingPower()*2/3 + 1))
  95. }
  96. }
  97. func (pol *POL) Description() string {
  98. if pol == nil {
  99. return "nil-POL"
  100. } else {
  101. return fmt.Sprintf("POL{H:%v R:%v BH:%X}", pol.Height, pol.Round,
  102. Fingerprint(pol.BlockHash), pol.BlockParts)
  103. }
  104. }