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.

183 lines
5.1 KiB

10 years ago
9 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 state
  2. import (
  3. "errors"
  4. "fmt"
  5. "io/ioutil"
  6. "math"
  7. "sync"
  8. "github.com/tendermint/tendermint/account"
  9. "github.com/tendermint/tendermint/binary"
  10. . "github.com/tendermint/tendermint/common"
  11. . "github.com/tendermint/tendermint/consensus/types"
  12. "github.com/tendermint/tendermint/types"
  13. "github.com/tendermint/tendermint/Godeps/_workspace/src/github.com/tendermint/ed25519"
  14. )
  15. const (
  16. stepNone = 0 // Used to distinguish the initial state
  17. stepPropose = 1
  18. stepPrevote = 2
  19. stepPrecommit = 3
  20. )
  21. func voteToStep(vote *types.Vote) uint8 {
  22. switch vote.Type {
  23. case types.VoteTypePrevote:
  24. return stepPrevote
  25. case types.VoteTypePrecommit:
  26. return stepPrecommit
  27. default:
  28. panic("Unknown vote type")
  29. }
  30. }
  31. type PrivValidator struct {
  32. Address []byte `json:"address"`
  33. PubKey account.PubKeyEd25519 `json:"pub_key"`
  34. PrivKey account.PrivKeyEd25519 `json:"priv_key"`
  35. LastHeight uint `json:"last_height"`
  36. LastRound uint `json:"last_round"`
  37. LastStep uint8 `json:"last_step"`
  38. // For persistence.
  39. // Overloaded for testing.
  40. filePath string
  41. mtx sync.Mutex
  42. }
  43. // Generates a new validator with private key.
  44. func GenPrivValidator() *PrivValidator {
  45. privKeyBytes := new([64]byte)
  46. copy(privKeyBytes[:32], CRandBytes(32))
  47. pubKeyBytes := ed25519.MakePublicKey(privKeyBytes)
  48. pubKey := account.PubKeyEd25519(pubKeyBytes[:])
  49. privKey := account.PrivKeyEd25519(privKeyBytes[:])
  50. return &PrivValidator{
  51. Address: pubKey.Address(),
  52. PubKey: pubKey,
  53. PrivKey: privKey,
  54. LastHeight: 0,
  55. LastRound: 0,
  56. LastStep: stepNone,
  57. filePath: "",
  58. }
  59. }
  60. func LoadPrivValidator(filePath string) *PrivValidator {
  61. privValJSONBytes, err := ioutil.ReadFile(filePath)
  62. if err != nil {
  63. panic(err)
  64. }
  65. privVal := binary.ReadJSON(&PrivValidator{}, privValJSONBytes, &err).(*PrivValidator)
  66. if err != nil {
  67. Exit(Fmt("Error reading PrivValidator from %v: %v\n", filePath, err))
  68. }
  69. privVal.filePath = filePath
  70. return privVal
  71. }
  72. func (privVal *PrivValidator) SetFile(filePath string) {
  73. privVal.mtx.Lock()
  74. defer privVal.mtx.Unlock()
  75. privVal.filePath = filePath
  76. }
  77. func (privVal *PrivValidator) Save() {
  78. privVal.mtx.Lock()
  79. defer privVal.mtx.Unlock()
  80. privVal.save()
  81. }
  82. func (privVal *PrivValidator) save() {
  83. if privVal.filePath == "" {
  84. panic("Cannot save PrivValidator: filePath not set")
  85. }
  86. jsonBytes := binary.JSONBytes(privVal)
  87. err := WriteFileAtomic(privVal.filePath, jsonBytes)
  88. if err != nil {
  89. // `@; BOOM!!!
  90. panic(err)
  91. }
  92. }
  93. func (privVal *PrivValidator) SignVote(chainID string, vote *types.Vote) error {
  94. privVal.mtx.Lock()
  95. defer privVal.mtx.Unlock()
  96. // If height regression, panic
  97. if privVal.LastHeight > vote.Height {
  98. return errors.New("Height regression in SignVote")
  99. }
  100. // More cases for when the height matches
  101. if privVal.LastHeight == vote.Height {
  102. // If round regression, panic
  103. if privVal.LastRound > vote.Round {
  104. return errors.New("Round regression in SignVote")
  105. }
  106. // If step regression, panic
  107. if privVal.LastRound == vote.Round && privVal.LastStep > voteToStep(vote) {
  108. return errors.New("Step regression in SignVote")
  109. }
  110. }
  111. // Persist height/round/step
  112. privVal.LastHeight = vote.Height
  113. privVal.LastRound = vote.Round
  114. privVal.LastStep = voteToStep(vote)
  115. privVal.save()
  116. // Sign
  117. privVal.SignVoteUnsafe(chainID, vote)
  118. return nil
  119. }
  120. func (privVal *PrivValidator) SignVoteUnsafe(chainID string, vote *types.Vote) {
  121. vote.Signature = privVal.PrivKey.Sign(account.SignBytes(chainID, vote)).(account.SignatureEd25519)
  122. }
  123. func (privVal *PrivValidator) SignProposal(chainID string, proposal *Proposal) error {
  124. privVal.mtx.Lock()
  125. defer privVal.mtx.Unlock()
  126. if privVal.LastHeight < proposal.Height ||
  127. privVal.LastHeight == proposal.Height && privVal.LastRound < proposal.Round ||
  128. privVal.LastHeight == 0 && privVal.LastRound == 0 && privVal.LastStep == stepNone {
  129. // Persist height/round/step
  130. privVal.LastHeight = proposal.Height
  131. privVal.LastRound = proposal.Round
  132. privVal.LastStep = stepPropose
  133. privVal.save()
  134. // Sign
  135. proposal.Signature = privVal.PrivKey.Sign(account.SignBytes(chainID, proposal)).(account.SignatureEd25519)
  136. return nil
  137. } else {
  138. return errors.New(fmt.Sprintf("Attempt of duplicate signing of proposal: Height %v, Round %v", proposal.Height, proposal.Round))
  139. }
  140. }
  141. func (privVal *PrivValidator) SignRebondTx(chainID string, rebondTx *types.RebondTx) error {
  142. privVal.mtx.Lock()
  143. defer privVal.mtx.Unlock()
  144. if privVal.LastHeight < rebondTx.Height {
  145. // Persist height/round/step
  146. privVal.LastHeight = rebondTx.Height
  147. privVal.LastRound = math.MaxUint64 // We can't do anything else for this rebondTx.Height.
  148. privVal.LastStep = math.MaxUint8
  149. privVal.save()
  150. // Sign
  151. rebondTx.Signature = privVal.PrivKey.Sign(account.SignBytes(chainID, rebondTx)).(account.SignatureEd25519)
  152. return nil
  153. } else {
  154. return errors.New(fmt.Sprintf("Attempt of duplicate signing of rebondTx: Height %v", rebondTx.Height))
  155. }
  156. }
  157. func (privVal *PrivValidator) String() string {
  158. return fmt.Sprintf("PrivValidator{%X LH:%v, LR:%v, LS:%v}", privVal.Address, privVal.LastHeight, privVal.LastRound, privVal.LastStep)
  159. }