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.

261 lines
6.9 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) GetAddress() []byte {
  146. return privVal.Address
  147. }
  148. func (privVal *PrivValidator) SignVote(chainID string, vote *Vote) error {
  149. privVal.mtx.Lock()
  150. defer privVal.mtx.Unlock()
  151. signature, err := privVal.signBytesHRS(vote.Height, vote.Round, voteToStep(vote), SignBytes(chainID, vote))
  152. if err != nil {
  153. return errors.New(Fmt("Error signing vote: %v", err))
  154. }
  155. vote.Signature = signature
  156. return nil
  157. }
  158. func (privVal *PrivValidator) SignProposal(chainID string, proposal *Proposal) error {
  159. privVal.mtx.Lock()
  160. defer privVal.mtx.Unlock()
  161. signature, err := privVal.signBytesHRS(proposal.Height, proposal.Round, stepPropose, SignBytes(chainID, proposal))
  162. if err != nil {
  163. return errors.New(Fmt("Error signing proposal: %v", err))
  164. }
  165. proposal.Signature = signature
  166. return nil
  167. }
  168. // check if there's a regression. Else sign and write the hrs+signature to disk
  169. func (privVal *PrivValidator) signBytesHRS(height, round int, step int8, signBytes []byte) (crypto.Signature, error) {
  170. // If height regression, err
  171. if privVal.LastHeight > height {
  172. return nil, errors.New("Height regression")
  173. }
  174. // More cases for when the height matches
  175. if privVal.LastHeight == height {
  176. // If round regression, err
  177. if privVal.LastRound > round {
  178. return nil, errors.New("Round regression")
  179. }
  180. // If step regression, err
  181. if privVal.LastRound == round {
  182. if privVal.LastStep > step {
  183. return nil, errors.New("Step regression")
  184. } else if privVal.LastStep == step {
  185. if privVal.LastSignBytes != nil {
  186. if privVal.LastSignature == nil {
  187. PanicSanity("privVal: LastSignature is nil but LastSignBytes is not!")
  188. }
  189. // so we dont sign a conflicting vote or proposal
  190. // NOTE: proposals are non-deterministic (include time),
  191. // so we can actually lose them, but will still never sign conflicting ones
  192. if bytes.Equal(privVal.LastSignBytes, signBytes) {
  193. log.Notice("Using privVal.LastSignature", "sig", privVal.LastSignature)
  194. return privVal.LastSignature, nil
  195. }
  196. }
  197. return nil, errors.New("Step regression")
  198. }
  199. }
  200. }
  201. // Sign
  202. signature := privVal.Sign(signBytes)
  203. // Persist height/round/step
  204. privVal.LastHeight = height
  205. privVal.LastRound = round
  206. privVal.LastStep = step
  207. privVal.LastSignature = signature
  208. privVal.LastSignBytes = signBytes
  209. privVal.save()
  210. return signature, nil
  211. }
  212. func (privVal *PrivValidator) String() string {
  213. return fmt.Sprintf("PrivValidator{%X LH:%v, LR:%v, LS:%v}", privVal.Address, privVal.LastHeight, privVal.LastRound, privVal.LastStep)
  214. }
  215. //-------------------------------------
  216. type PrivValidatorsByAddress []*PrivValidator
  217. func (pvs PrivValidatorsByAddress) Len() int {
  218. return len(pvs)
  219. }
  220. func (pvs PrivValidatorsByAddress) Less(i, j int) bool {
  221. return bytes.Compare(pvs[i].Address, pvs[j].Address) == -1
  222. }
  223. func (pvs PrivValidatorsByAddress) Swap(i, j int) {
  224. it := pvs[i]
  225. pvs[i] = pvs[j]
  226. pvs[j] = it
  227. }