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.

256 lines
6.8 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
  1. package types
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "io/ioutil"
  7. "os"
  8. "sync"
  9. . "github.com/tendermint/go-common"
  10. "github.com/tendermint/go-crypto"
  11. "github.com/tendermint/go-wire"
  12. "github.com/tendermint/ed25519"
  13. )
  14. const (
  15. stepNone = 0 // Used to distinguish the initial state
  16. stepPropose = 1
  17. stepPrevote = 2
  18. stepPrecommit = 3
  19. )
  20. func voteToStep(vote *Vote) int8 {
  21. switch vote.Type {
  22. case VoteTypePrevote:
  23. return stepPrevote
  24. case VoteTypePrecommit:
  25. return stepPrecommit
  26. default:
  27. PanicSanity("Unknown vote type")
  28. return 0
  29. }
  30. }
  31. type PrivValidator struct {
  32. Address []byte `json:"address"`
  33. PubKey crypto.PubKey `json:"pub_key"`
  34. LastHeight int `json:"last_height"`
  35. LastRound int `json:"last_round"`
  36. LastStep int8 `json:"last_step"`
  37. LastSignature crypto.Signature `json:"last_signature"` // so we dont lose signatures
  38. LastSignBytes []byte `json:"last_signbytes"` // so we dont lose signatures
  39. // PrivKey should be empty if a Signer other than the default is being used.
  40. PrivKey crypto.PrivKey `json:"priv_key"`
  41. Signer `json:"-"`
  42. // For persistence.
  43. // Overloaded for testing.
  44. filePath string
  45. mtx sync.Mutex
  46. }
  47. // This is used to sign votes.
  48. // It is the caller's duty to verify the msg before calling Sign,
  49. // eg. to avoid double signing.
  50. // Currently, the only callers are SignVote and SignProposal
  51. type Signer interface {
  52. Sign(msg []byte) crypto.Signature
  53. }
  54. // Implements Signer
  55. type DefaultSigner struct {
  56. priv crypto.PrivKey
  57. }
  58. func NewDefaultSigner(priv crypto.PrivKey) *DefaultSigner {
  59. return &DefaultSigner{priv: priv}
  60. }
  61. // Implements Signer
  62. func (ds *DefaultSigner) Sign(msg []byte) crypto.Signature {
  63. return ds.priv.Sign(msg)
  64. }
  65. func (privVal *PrivValidator) SetSigner(s Signer) {
  66. privVal.Signer = s
  67. }
  68. // Generates a new validator with private key.
  69. func GenPrivValidator() *PrivValidator {
  70. privKeyBytes := new([64]byte)
  71. copy(privKeyBytes[:32], crypto.CRandBytes(32))
  72. pubKeyBytes := ed25519.MakePublicKey(privKeyBytes)
  73. pubKey := crypto.PubKeyEd25519(*pubKeyBytes)
  74. privKey := crypto.PrivKeyEd25519(*privKeyBytes)
  75. return &PrivValidator{
  76. Address: pubKey.Address(),
  77. PubKey: pubKey,
  78. PrivKey: privKey,
  79. LastHeight: 0,
  80. LastRound: 0,
  81. LastStep: stepNone,
  82. LastSignature: nil,
  83. LastSignBytes: nil,
  84. filePath: "",
  85. Signer: NewDefaultSigner(privKey),
  86. }
  87. }
  88. func LoadPrivValidator(filePath string) *PrivValidator {
  89. privValJSONBytes, err := ioutil.ReadFile(filePath)
  90. if err != nil {
  91. Exit(err.Error())
  92. }
  93. privVal := wire.ReadJSON(&PrivValidator{}, privValJSONBytes, &err).(*PrivValidator)
  94. if err != nil {
  95. Exit(Fmt("Error reading PrivValidator from %v: %v\n", filePath, err))
  96. }
  97. privVal.filePath = filePath
  98. privVal.Signer = NewDefaultSigner(privVal.PrivKey)
  99. return privVal
  100. }
  101. func LoadOrGenPrivValidator(filePath string) *PrivValidator {
  102. var privValidator *PrivValidator
  103. if _, err := os.Stat(filePath); err == nil {
  104. privValidator = LoadPrivValidator(filePath)
  105. log.Notice("Loaded PrivValidator",
  106. "file", filePath, "privValidator", privValidator)
  107. } else {
  108. privValidator = GenPrivValidator()
  109. privValidator.SetFile(filePath)
  110. privValidator.Save()
  111. log.Notice("Generated PrivValidator", "file", filePath)
  112. }
  113. return privValidator
  114. }
  115. func (privVal *PrivValidator) SetFile(filePath string) {
  116. privVal.mtx.Lock()
  117. defer privVal.mtx.Unlock()
  118. privVal.filePath = filePath
  119. }
  120. func (privVal *PrivValidator) Save() {
  121. privVal.mtx.Lock()
  122. defer privVal.mtx.Unlock()
  123. privVal.save()
  124. }
  125. func (privVal *PrivValidator) save() {
  126. if privVal.filePath == "" {
  127. PanicSanity("Cannot save PrivValidator: filePath not set")
  128. }
  129. jsonBytes := wire.JSONBytesPretty(privVal)
  130. err := WriteFileAtomic(privVal.filePath, jsonBytes, 0600)
  131. if err != nil {
  132. // `@; BOOM!!!
  133. PanicCrisis(err)
  134. }
  135. }
  136. // NOTE: Unsafe!
  137. func (privVal *PrivValidator) Reset() {
  138. privVal.LastHeight = 0
  139. privVal.LastRound = 0
  140. privVal.LastStep = 0
  141. privVal.LastSignature = nil
  142. privVal.LastSignBytes = nil
  143. privVal.Save()
  144. }
  145. func (privVal *PrivValidator) SignVote(chainID string, vote *Vote) error {
  146. privVal.mtx.Lock()
  147. defer privVal.mtx.Unlock()
  148. signature, err := privVal.signBytesHRS(vote.Height, vote.Round, voteToStep(vote), SignBytes(chainID, vote))
  149. if err != nil {
  150. return errors.New(Fmt("Error signing vote: %v", err))
  151. }
  152. vote.Signature = signature.(crypto.SignatureEd25519)
  153. return nil
  154. }
  155. func (privVal *PrivValidator) SignProposal(chainID string, proposal *Proposal) error {
  156. privVal.mtx.Lock()
  157. defer privVal.mtx.Unlock()
  158. signature, err := privVal.signBytesHRS(proposal.Height, proposal.Round, stepPropose, SignBytes(chainID, proposal))
  159. if err != nil {
  160. return errors.New(Fmt("Error signing proposal: %v", err))
  161. }
  162. proposal.Signature = signature.(crypto.SignatureEd25519)
  163. return nil
  164. }
  165. // check if there's a regression. Else sign and write the hrs+signature to disk
  166. func (privVal *PrivValidator) signBytesHRS(height, round int, step int8, signBytes []byte) (crypto.Signature, error) {
  167. // If height regression, err
  168. if privVal.LastHeight > height {
  169. return nil, errors.New("Height regression")
  170. }
  171. // More cases for when the height matches
  172. if privVal.LastHeight == height {
  173. // If round regression, err
  174. if privVal.LastRound > round {
  175. return nil, errors.New("Round regression")
  176. }
  177. // If step regression, err
  178. if privVal.LastRound == round {
  179. if privVal.LastStep > step {
  180. return nil, errors.New("Step regression")
  181. } else if privVal.LastStep == step {
  182. if privVal.LastSignBytes != nil {
  183. if privVal.LastSignature == nil {
  184. PanicSanity("privVal: LastSignature is nil but LastSignBytes is not!")
  185. }
  186. // so we dont sign a conflicting vote or proposal
  187. // NOTE: proposals are non-deterministic (include time),
  188. // so we can actually lose them, but will still never sign conflicting ones
  189. if bytes.Equal(privVal.LastSignBytes, signBytes) {
  190. log.Notice("Using privVal.LastSignature", "sig", privVal.LastSignature)
  191. return privVal.LastSignature, nil
  192. }
  193. }
  194. return nil, errors.New("Step regression")
  195. }
  196. }
  197. }
  198. // Sign
  199. signature := privVal.Sign(signBytes)
  200. // Persist height/round/step
  201. privVal.LastHeight = height
  202. privVal.LastRound = round
  203. privVal.LastStep = step
  204. privVal.LastSignature = signature
  205. privVal.LastSignBytes = signBytes
  206. privVal.save()
  207. return signature, nil
  208. }
  209. func (privVal *PrivValidator) String() string {
  210. return fmt.Sprintf("PrivValidator{%X LH:%v, LR:%v, LS:%v}", privVal.Address, privVal.LastHeight, privVal.LastRound, privVal.LastStep)
  211. }
  212. //-------------------------------------
  213. type PrivValidatorsByAddress []*PrivValidator
  214. func (pvs PrivValidatorsByAddress) Len() int {
  215. return len(pvs)
  216. }
  217. func (pvs PrivValidatorsByAddress) Less(i, j int) bool {
  218. return bytes.Compare(pvs[i].Address, pvs[j].Address) == -1
  219. }
  220. func (pvs PrivValidatorsByAddress) Swap(i, j int) {
  221. it := pvs[i]
  222. pvs[i] = pvs[j]
  223. pvs[j] = it
  224. }