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.

275 lines
7.1 KiB

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