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.

372 lines
12 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. package types
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "io/ioutil"
  8. "os"
  9. "sync"
  10. "time"
  11. crypto "github.com/tendermint/go-crypto"
  12. data "github.com/tendermint/go-wire/data"
  13. cmn "github.com/tendermint/tmlibs/common"
  14. )
  15. // TODO: type ?
  16. const (
  17. stepNone = 0 // Used to distinguish the initial state
  18. stepPropose = 1
  19. stepPrevote = 2
  20. stepPrecommit = 3
  21. )
  22. func voteToStep(vote *Vote) int8 {
  23. switch vote.Type {
  24. case VoteTypePrevote:
  25. return stepPrevote
  26. case VoteTypePrecommit:
  27. return stepPrecommit
  28. default:
  29. cmn.PanicSanity("Unknown vote type")
  30. return 0
  31. }
  32. }
  33. // PrivValidator defines the functionality of a local Tendermint validator
  34. // that signs votes, proposals, and heartbeats, and never double signs.
  35. type PrivValidator interface {
  36. GetAddress() data.Bytes // redundant since .PubKey().Address()
  37. GetPubKey() crypto.PubKey
  38. SignVote(chainID string, vote *Vote) error
  39. SignProposal(chainID string, proposal *Proposal) error
  40. SignHeartbeat(chainID string, heartbeat *Heartbeat) error
  41. }
  42. // PrivValidatorFS implements PrivValidator using data persisted to disk
  43. // to prevent double signing. The Signer itself can be mutated to use
  44. // something besides the default, for instance a hardware signer.
  45. type PrivValidatorFS struct {
  46. Address data.Bytes `json:"address"`
  47. PubKey crypto.PubKey `json:"pub_key"`
  48. LastHeight int64 `json:"last_height"`
  49. LastRound int `json:"last_round"`
  50. LastStep int8 `json:"last_step"`
  51. LastSignature crypto.Signature `json:"last_signature,omitempty"` // so we dont lose signatures
  52. LastSignBytes data.Bytes `json:"last_signbytes,omitempty"` // so we dont lose signatures
  53. // PrivKey should be empty if a Signer other than the default is being used.
  54. PrivKey crypto.PrivKey `json:"priv_key"`
  55. Signer `json:"-"`
  56. // For persistence.
  57. // Overloaded for testing.
  58. filePath string
  59. mtx sync.Mutex
  60. }
  61. // Signer is an interface that defines how to sign messages.
  62. // It is the caller's duty to verify the msg before calling Sign,
  63. // eg. to avoid double signing.
  64. // Currently, the only callers are SignVote, SignProposal, and SignHeartbeat.
  65. type Signer interface {
  66. Sign(msg []byte) (crypto.Signature, error)
  67. }
  68. // DefaultSigner implements Signer.
  69. // It uses a standard, unencrypted crypto.PrivKey.
  70. type DefaultSigner struct {
  71. PrivKey crypto.PrivKey `json:"priv_key"`
  72. }
  73. // NewDefaultSigner returns an instance of DefaultSigner.
  74. func NewDefaultSigner(priv crypto.PrivKey) *DefaultSigner {
  75. return &DefaultSigner{
  76. PrivKey: priv,
  77. }
  78. }
  79. // Sign implements Signer. It signs the byte slice with a private key.
  80. func (ds *DefaultSigner) Sign(msg []byte) (crypto.Signature, error) {
  81. return ds.PrivKey.Sign(msg), nil
  82. }
  83. // GetAddress returns the address of the validator.
  84. // Implements PrivValidator.
  85. func (pv *PrivValidatorFS) GetAddress() data.Bytes {
  86. return pv.Address
  87. }
  88. // GetPubKey returns the public key of the validator.
  89. // Implements PrivValidator.
  90. func (pv *PrivValidatorFS) GetPubKey() crypto.PubKey {
  91. return pv.PubKey
  92. }
  93. // GenPrivValidatorFS generates a new validator with randomly generated private key
  94. // and sets the filePath, but does not call Save().
  95. func GenPrivValidatorFS(filePath string) *PrivValidatorFS {
  96. privKey := crypto.GenPrivKeyEd25519().Wrap()
  97. return &PrivValidatorFS{
  98. Address: privKey.PubKey().Address(),
  99. PubKey: privKey.PubKey(),
  100. PrivKey: privKey,
  101. LastStep: stepNone,
  102. Signer: NewDefaultSigner(privKey),
  103. filePath: filePath,
  104. }
  105. }
  106. // LoadPrivValidatorFS loads a PrivValidatorFS from the filePath.
  107. func LoadPrivValidatorFS(filePath string) *PrivValidatorFS {
  108. return LoadPrivValidatorFSWithSigner(filePath, func(privVal PrivValidator) Signer {
  109. return NewDefaultSigner(privVal.(*PrivValidatorFS).PrivKey)
  110. })
  111. }
  112. // LoadOrGenPrivValidatorFS loads a PrivValidatorFS from the given filePath
  113. // or else generates a new one and saves it to the filePath.
  114. func LoadOrGenPrivValidatorFS(filePath string) *PrivValidatorFS {
  115. var privVal *PrivValidatorFS
  116. if _, err := os.Stat(filePath); err == nil {
  117. privVal = LoadPrivValidatorFS(filePath)
  118. } else {
  119. privVal = GenPrivValidatorFS(filePath)
  120. privVal.Save()
  121. }
  122. return privVal
  123. }
  124. // LoadPrivValidatorWithSigner loads a PrivValidatorFS with a custom
  125. // signer object. The PrivValidatorFS handles double signing prevention by persisting
  126. // data to the filePath, while the Signer handles the signing.
  127. // If the filePath does not exist, the PrivValidatorFS must be created manually and saved.
  128. func LoadPrivValidatorFSWithSigner(filePath string, signerFunc func(PrivValidator) Signer) *PrivValidatorFS {
  129. privValJSONBytes, err := ioutil.ReadFile(filePath)
  130. if err != nil {
  131. cmn.Exit(err.Error())
  132. }
  133. privVal := &PrivValidatorFS{}
  134. err = json.Unmarshal(privValJSONBytes, &privVal)
  135. if err != nil {
  136. cmn.Exit(cmn.Fmt("Error reading PrivValidator from %v: %v\n", filePath, err))
  137. }
  138. privVal.filePath = filePath
  139. privVal.Signer = signerFunc(privVal)
  140. return privVal
  141. }
  142. // Save persists the PrivValidatorFS to disk.
  143. func (privVal *PrivValidatorFS) Save() {
  144. privVal.mtx.Lock()
  145. defer privVal.mtx.Unlock()
  146. privVal.save()
  147. }
  148. func (privVal *PrivValidatorFS) save() {
  149. if privVal.filePath == "" {
  150. cmn.PanicSanity("Cannot save PrivValidator: filePath not set")
  151. }
  152. jsonBytes, err := json.Marshal(privVal)
  153. if err != nil {
  154. // `@; BOOM!!!
  155. cmn.PanicCrisis(err)
  156. }
  157. err = cmn.WriteFileAtomic(privVal.filePath, jsonBytes, 0600)
  158. if err != nil {
  159. // `@; BOOM!!!
  160. cmn.PanicCrisis(err)
  161. }
  162. }
  163. // Reset resets all fields in the PrivValidatorFS.
  164. // NOTE: Unsafe!
  165. func (privVal *PrivValidatorFS) Reset() {
  166. privVal.LastHeight = 0
  167. privVal.LastRound = 0
  168. privVal.LastStep = 0
  169. privVal.LastSignature = crypto.Signature{}
  170. privVal.LastSignBytes = nil
  171. privVal.Save()
  172. }
  173. // SignVote signs a canonical representation of the vote, along with the
  174. // chainID. Implements PrivValidator.
  175. func (privVal *PrivValidatorFS) SignVote(chainID string, vote *Vote) error {
  176. privVal.mtx.Lock()
  177. defer privVal.mtx.Unlock()
  178. signature, err := privVal.signBytesHRS(vote.Height, vote.Round, voteToStep(vote),
  179. SignBytes(chainID, vote), checkVotesOnlyDifferByTimestamp)
  180. if err != nil {
  181. return errors.New(cmn.Fmt("Error signing vote: %v", err))
  182. }
  183. vote.Signature = signature
  184. return nil
  185. }
  186. // SignProposal signs a canonical representation of the proposal, along with
  187. // the chainID. Implements PrivValidator.
  188. func (privVal *PrivValidatorFS) SignProposal(chainID string, proposal *Proposal) error {
  189. privVal.mtx.Lock()
  190. defer privVal.mtx.Unlock()
  191. signature, err := privVal.signBytesHRS(proposal.Height, proposal.Round, stepPropose,
  192. SignBytes(chainID, proposal), checkProposalsOnlyDifferByTimestamp)
  193. if err != nil {
  194. return fmt.Errorf("Error signing proposal: %v", err)
  195. }
  196. proposal.Signature = signature
  197. return nil
  198. }
  199. // returns error if HRS regression or no LastSignBytes. returns true if HRS is unchanged
  200. func (privVal *PrivValidatorFS) checkHRS(height int64, round int, step int8) (bool, error) {
  201. if privVal.LastHeight > height {
  202. return false, errors.New("Height regression")
  203. }
  204. if privVal.LastHeight == height {
  205. if privVal.LastRound > round {
  206. return false, errors.New("Round regression")
  207. }
  208. if privVal.LastRound == round {
  209. if privVal.LastStep > step {
  210. return false, errors.New("Step regression")
  211. } else if privVal.LastStep == step {
  212. if privVal.LastSignBytes != nil {
  213. if privVal.LastSignature.Empty() {
  214. panic("privVal: LastSignature is nil but LastSignBytes is not!")
  215. }
  216. return true, nil
  217. }
  218. return false, errors.New("No LastSignature found")
  219. }
  220. }
  221. }
  222. return false, nil
  223. }
  224. // signBytesHRS signs the given signBytes if the height/round/step (HRS) are
  225. // greater than the latest state. If the HRS are equal and the only thing changed is the timestamp,
  226. // it returns the privValidator.LastSignature. Else it returns an error.
  227. func (privVal *PrivValidatorFS) signBytesHRS(height int64, round int, step int8,
  228. signBytes []byte, checkFn checkOnlyDifferByTimestamp) (crypto.Signature, error) {
  229. sig := crypto.Signature{}
  230. sameHRS, err := privVal.checkHRS(height, round, step)
  231. if err != nil {
  232. return sig, err
  233. }
  234. // We might crash before writing to the wal,
  235. // causing us to try to re-sign for the same HRS
  236. if sameHRS {
  237. // if they're the same or only differ by timestamp,
  238. // return the LastSignature. Otherwise, error
  239. if bytes.Equal(signBytes, privVal.LastSignBytes) ||
  240. checkFn(privVal.LastSignBytes, signBytes) {
  241. return privVal.LastSignature, nil
  242. }
  243. return sig, fmt.Errorf("Conflicting data")
  244. }
  245. sig, err = privVal.Sign(signBytes)
  246. if err != nil {
  247. return sig, err
  248. }
  249. privVal.saveSigned(height, round, step, signBytes, sig)
  250. return sig, nil
  251. }
  252. // Persist height/round/step and signature
  253. func (privVal *PrivValidatorFS) saveSigned(height int64, round int, step int8,
  254. signBytes []byte, sig crypto.Signature) {
  255. privVal.LastHeight = height
  256. privVal.LastRound = round
  257. privVal.LastStep = step
  258. privVal.LastSignature = sig
  259. privVal.LastSignBytes = signBytes
  260. privVal.save()
  261. }
  262. // SignHeartbeat signs a canonical representation of the heartbeat, along with the chainID.
  263. // Implements PrivValidator.
  264. func (privVal *PrivValidatorFS) SignHeartbeat(chainID string, heartbeat *Heartbeat) error {
  265. privVal.mtx.Lock()
  266. defer privVal.mtx.Unlock()
  267. var err error
  268. heartbeat.Signature, err = privVal.Sign(SignBytes(chainID, heartbeat))
  269. return err
  270. }
  271. // String returns a string representation of the PrivValidatorFS.
  272. func (privVal *PrivValidatorFS) String() string {
  273. return fmt.Sprintf("PrivValidator{%v LH:%v, LR:%v, LS:%v}", privVal.GetAddress(), privVal.LastHeight, privVal.LastRound, privVal.LastStep)
  274. }
  275. //-------------------------------------
  276. type PrivValidatorsByAddress []*PrivValidatorFS
  277. func (pvs PrivValidatorsByAddress) Len() int {
  278. return len(pvs)
  279. }
  280. func (pvs PrivValidatorsByAddress) Less(i, j int) bool {
  281. return bytes.Compare(pvs[i].GetAddress(), pvs[j].GetAddress()) == -1
  282. }
  283. func (pvs PrivValidatorsByAddress) Swap(i, j int) {
  284. it := pvs[i]
  285. pvs[i] = pvs[j]
  286. pvs[j] = it
  287. }
  288. //-------------------------------------
  289. type checkOnlyDifferByTimestamp func([]byte, []byte) bool
  290. // returns true if the only difference in the votes is their timestamp
  291. func checkVotesOnlyDifferByTimestamp(lastSignBytes, newSignBytes []byte) bool {
  292. var lastVote, newVote CanonicalJSONOnceVote
  293. if err := json.Unmarshal(lastSignBytes, &lastVote); err != nil {
  294. panic(fmt.Sprintf("LastSignBytes cannot be unmarshalled into vote: %v", err))
  295. }
  296. if err := json.Unmarshal(newSignBytes, &newVote); err != nil {
  297. panic(fmt.Sprintf("signBytes cannot be unmarshalled into vote: %v", err))
  298. }
  299. // set the times to the same value and check equality
  300. now := CanonicalTime(time.Now())
  301. lastVote.Vote.Timestamp = now
  302. newVote.Vote.Timestamp = now
  303. lastVoteBytes, _ := json.Marshal(lastVote)
  304. newVoteBytes, _ := json.Marshal(newVote)
  305. return bytes.Equal(newVoteBytes, lastVoteBytes)
  306. }
  307. // returns true if the only difference in the proposals is their timestamp
  308. func checkProposalsOnlyDifferByTimestamp(lastSignBytes, newSignBytes []byte) bool {
  309. var lastProposal, newProposal CanonicalJSONOnceProposal
  310. if err := json.Unmarshal(lastSignBytes, &lastProposal); err != nil {
  311. panic(fmt.Sprintf("LastSignBytes cannot be unmarshalled into proposal: %v", err))
  312. }
  313. if err := json.Unmarshal(newSignBytes, &newProposal); err != nil {
  314. panic(fmt.Sprintf("signBytes cannot be unmarshalled into proposal: %v", err))
  315. }
  316. // set the times to the same value and check equality
  317. now := CanonicalTime(time.Now())
  318. lastProposal.Proposal.Timestamp = now
  319. newProposal.Proposal.Timestamp = now
  320. lastProposalBytes, _ := json.Marshal(lastProposal)
  321. newProposalBytes, _ := json.Marshal(newProposal)
  322. return bytes.Equal(newProposalBytes, lastProposalBytes)
  323. }