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.

422 lines
13 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 int8 = 0 // Used to distinguish the initial state
  18. stepPropose int8 = 1
  19. stepPrevote int8 = 2
  20. stepPrecommit int8 = 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. if err := privVal.signVote(chainID, vote); err != nil {
  179. return errors.New(cmn.Fmt("Error signing vote: %v", err))
  180. }
  181. return nil
  182. }
  183. // SignProposal signs a canonical representation of the proposal, along with
  184. // the chainID. Implements PrivValidator.
  185. func (privVal *PrivValidatorFS) SignProposal(chainID string, proposal *Proposal) error {
  186. privVal.mtx.Lock()
  187. defer privVal.mtx.Unlock()
  188. if err := privVal.signProposal(chainID, proposal); err != nil {
  189. return fmt.Errorf("Error signing proposal: %v", err)
  190. }
  191. return nil
  192. }
  193. // returns error if HRS regression or no LastSignBytes. returns true if HRS is unchanged
  194. func (privVal *PrivValidatorFS) checkHRS(height int64, round int, step int8) (bool, error) {
  195. if privVal.LastHeight > height {
  196. return false, errors.New("Height regression")
  197. }
  198. if privVal.LastHeight == height {
  199. if privVal.LastRound > round {
  200. return false, errors.New("Round regression")
  201. }
  202. if privVal.LastRound == round {
  203. if privVal.LastStep > step {
  204. return false, errors.New("Step regression")
  205. } else if privVal.LastStep == step {
  206. if privVal.LastSignBytes != nil {
  207. if privVal.LastSignature.Empty() {
  208. panic("privVal: LastSignature is nil but LastSignBytes is not!")
  209. }
  210. return true, nil
  211. }
  212. return false, errors.New("No LastSignature found")
  213. }
  214. }
  215. }
  216. return false, nil
  217. }
  218. // signVote checks if the vote is good to sign and sets the vote signature.
  219. // It may need to set the timestamp as well if the vote is otherwise the same as
  220. // a previously signed vote (ie. we crashed after signing but before the vote hit the WAL).
  221. func (privVal *PrivValidatorFS) signVote(chainID string, vote *Vote) error {
  222. height, round, step := vote.Height, vote.Round, voteToStep(vote)
  223. signBytes := SignBytes(chainID, vote)
  224. sameHRS, err := privVal.checkHRS(height, round, step)
  225. if err != nil {
  226. return err
  227. }
  228. // We might crash before writing to the wal,
  229. // causing us to try to re-sign for the same HRS.
  230. // If signbytes are the same, use the last signature.
  231. // If they only differ by timestamp, use last timestamp and signature
  232. // Otherwise, return error
  233. if sameHRS {
  234. if bytes.Equal(signBytes, privVal.LastSignBytes) {
  235. vote.Signature = privVal.LastSignature
  236. } else if timestamp, ok := checkVotesOnlyDifferByTimestamp(privVal.LastSignBytes, signBytes); ok {
  237. vote.Timestamp = timestamp
  238. vote.Signature = privVal.LastSignature
  239. } else {
  240. err = fmt.Errorf("Conflicting data")
  241. }
  242. return err
  243. }
  244. // It passed the checks. Sign the vote
  245. sig, err := privVal.Sign(signBytes)
  246. if err != nil {
  247. return err
  248. }
  249. privVal.saveSigned(height, round, step, signBytes, sig)
  250. vote.Signature = sig
  251. return nil
  252. }
  253. // signProposal checks if the proposal is good to sign and sets the proposal signature.
  254. // It may need to set the timestamp as well if the proposal is otherwise the same as
  255. // a previously signed proposal ie. we crashed after signing but before the proposal hit the WAL).
  256. func (privVal *PrivValidatorFS) signProposal(chainID string, proposal *Proposal) error {
  257. height, round, step := proposal.Height, proposal.Round, stepPropose
  258. signBytes := SignBytes(chainID, proposal)
  259. sameHRS, err := privVal.checkHRS(height, round, step)
  260. if err != nil {
  261. return err
  262. }
  263. // We might crash before writing to the wal,
  264. // causing us to try to re-sign for the same HRS.
  265. // If signbytes are the same, use the last signature.
  266. // If they only differ by timestamp, use last timestamp and signature
  267. // Otherwise, return error
  268. if sameHRS {
  269. if bytes.Equal(signBytes, privVal.LastSignBytes) {
  270. proposal.Signature = privVal.LastSignature
  271. } else if timestamp, ok := checkProposalsOnlyDifferByTimestamp(privVal.LastSignBytes, signBytes); ok {
  272. proposal.Timestamp = timestamp
  273. proposal.Signature = privVal.LastSignature
  274. } else {
  275. err = fmt.Errorf("Conflicting data")
  276. }
  277. return err
  278. }
  279. // It passed the checks. Sign the proposal
  280. sig, err := privVal.Sign(signBytes)
  281. if err != nil {
  282. return err
  283. }
  284. privVal.saveSigned(height, round, step, signBytes, sig)
  285. proposal.Signature = sig
  286. return nil
  287. }
  288. // Persist height/round/step and signature
  289. func (privVal *PrivValidatorFS) saveSigned(height int64, round int, step int8,
  290. signBytes []byte, sig crypto.Signature) {
  291. privVal.LastHeight = height
  292. privVal.LastRound = round
  293. privVal.LastStep = step
  294. privVal.LastSignature = sig
  295. privVal.LastSignBytes = signBytes
  296. privVal.save()
  297. }
  298. // SignHeartbeat signs a canonical representation of the heartbeat, along with the chainID.
  299. // Implements PrivValidator.
  300. func (privVal *PrivValidatorFS) SignHeartbeat(chainID string, heartbeat *Heartbeat) error {
  301. privVal.mtx.Lock()
  302. defer privVal.mtx.Unlock()
  303. var err error
  304. heartbeat.Signature, err = privVal.Sign(SignBytes(chainID, heartbeat))
  305. return err
  306. }
  307. // String returns a string representation of the PrivValidatorFS.
  308. func (privVal *PrivValidatorFS) String() string {
  309. return fmt.Sprintf("PrivValidator{%v LH:%v, LR:%v, LS:%v}", privVal.GetAddress(), privVal.LastHeight, privVal.LastRound, privVal.LastStep)
  310. }
  311. //-------------------------------------
  312. type PrivValidatorsByAddress []*PrivValidatorFS
  313. func (pvs PrivValidatorsByAddress) Len() int {
  314. return len(pvs)
  315. }
  316. func (pvs PrivValidatorsByAddress) Less(i, j int) bool {
  317. return bytes.Compare(pvs[i].GetAddress(), pvs[j].GetAddress()) == -1
  318. }
  319. func (pvs PrivValidatorsByAddress) Swap(i, j int) {
  320. it := pvs[i]
  321. pvs[i] = pvs[j]
  322. pvs[j] = it
  323. }
  324. //-------------------------------------
  325. // returns the timestamp from the lastSignBytes.
  326. // returns true if the only difference in the votes is their timestamp.
  327. func checkVotesOnlyDifferByTimestamp(lastSignBytes, newSignBytes []byte) (time.Time, bool) {
  328. var lastVote, newVote CanonicalJSONOnceVote
  329. if err := json.Unmarshal(lastSignBytes, &lastVote); err != nil {
  330. panic(fmt.Sprintf("LastSignBytes cannot be unmarshalled into vote: %v", err))
  331. }
  332. if err := json.Unmarshal(newSignBytes, &newVote); err != nil {
  333. panic(fmt.Sprintf("signBytes cannot be unmarshalled into vote: %v", err))
  334. }
  335. lastTime, err := time.Parse(timeFormat, lastVote.Vote.Timestamp)
  336. if err != nil {
  337. panic(err)
  338. }
  339. // set the times to the same value and check equality
  340. now := CanonicalTime(time.Now())
  341. lastVote.Vote.Timestamp = now
  342. newVote.Vote.Timestamp = now
  343. lastVoteBytes, _ := json.Marshal(lastVote)
  344. newVoteBytes, _ := json.Marshal(newVote)
  345. return lastTime, bytes.Equal(newVoteBytes, lastVoteBytes)
  346. }
  347. // returns the timestamp from the lastSignBytes.
  348. // returns true if the only difference in the proposals is their timestamp
  349. func checkProposalsOnlyDifferByTimestamp(lastSignBytes, newSignBytes []byte) (time.Time, bool) {
  350. var lastProposal, newProposal CanonicalJSONOnceProposal
  351. if err := json.Unmarshal(lastSignBytes, &lastProposal); err != nil {
  352. panic(fmt.Sprintf("LastSignBytes cannot be unmarshalled into proposal: %v", err))
  353. }
  354. if err := json.Unmarshal(newSignBytes, &newProposal); err != nil {
  355. panic(fmt.Sprintf("signBytes cannot be unmarshalled into proposal: %v", err))
  356. }
  357. lastTime, err := time.Parse(timeFormat, lastProposal.Proposal.Timestamp)
  358. if err != nil {
  359. panic(err)
  360. }
  361. // set the times to the same value and check equality
  362. now := CanonicalTime(time.Now())
  363. lastProposal.Proposal.Timestamp = now
  364. newProposal.Proposal.Timestamp = now
  365. lastProposalBytes, _ := json.Marshal(lastProposal)
  366. newProposalBytes, _ := json.Marshal(newProposal)
  367. return lastTime, bytes.Equal(newProposalBytes, lastProposalBytes)
  368. }