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.

212 lines
5.6 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
10 years ago
10 years ago
  1. package state
  2. // TODO: This logic is crude. Should be more transactional.
  3. import (
  4. "bytes"
  5. "encoding/base64"
  6. "encoding/json"
  7. "fmt"
  8. "io/ioutil"
  9. "math"
  10. . "github.com/tendermint/tendermint/account"
  11. . "github.com/tendermint/tendermint/binary"
  12. . "github.com/tendermint/tendermint/block"
  13. . "github.com/tendermint/tendermint/common"
  14. . "github.com/tendermint/tendermint/config"
  15. . "github.com/tendermint/tendermint/consensus/types"
  16. "github.com/tendermint/go-ed25519"
  17. )
  18. const (
  19. stepNone = 0 // Used to distinguish the initial state
  20. stepPropose = 1
  21. stepPrevote = 2
  22. stepPrecommit = 3
  23. stepCommit = 4
  24. )
  25. func voteToStep(vote *Vote) uint8 {
  26. switch vote.Type {
  27. case VoteTypePrevote:
  28. return stepPrevote
  29. case VoteTypePrecommit:
  30. return stepPrecommit
  31. case VoteTypeCommit:
  32. return stepCommit
  33. default:
  34. panic("Unknown vote type")
  35. }
  36. }
  37. type PrivValidator struct {
  38. Address []byte
  39. PubKey PubKeyEd25519
  40. PrivKey PrivKeyEd25519
  41. LastHeight uint
  42. LastRound uint
  43. LastStep uint8
  44. // For persistence.
  45. // Overloaded for testing.
  46. filename string
  47. }
  48. // Generates a new validator with private key.
  49. func GenPrivValidator() *PrivValidator {
  50. privKeyBytes := CRandBytes(32)
  51. pubKeyBytes := ed25519.MakePubKey(privKeyBytes)
  52. pubKey := PubKeyEd25519{pubKeyBytes}
  53. privKey := PrivKeyEd25519{pubKeyBytes, privKeyBytes}
  54. return &PrivValidator{
  55. Address: pubKey.Address(),
  56. PubKey: pubKey,
  57. PrivKey: privKey,
  58. LastHeight: 0,
  59. LastRound: 0,
  60. LastStep: stepNone,
  61. filename: PrivValidatorFile(),
  62. }
  63. }
  64. type PrivValidatorJSON struct {
  65. Address string
  66. PubKey string
  67. PrivKey string
  68. LastHeight uint
  69. LastRound uint
  70. LastStep uint8
  71. }
  72. func LoadPrivValidator() *PrivValidator {
  73. privValJSONBytes, err := ioutil.ReadFile(PrivValidatorFile())
  74. if err != nil {
  75. panic(err)
  76. }
  77. privValJSON := PrivValidatorJSON{}
  78. err = json.Unmarshal(privValJSONBytes, &privValJSON)
  79. if err != nil {
  80. panic(err)
  81. }
  82. address, err := base64.StdEncoding.DecodeString(privValJSON.Address)
  83. if err != nil {
  84. panic(err)
  85. }
  86. pubKeyBytes, err := base64.StdEncoding.DecodeString(privValJSON.PubKey)
  87. if err != nil {
  88. panic(err)
  89. }
  90. privKeyBytes, err := base64.StdEncoding.DecodeString(privValJSON.PrivKey)
  91. if err != nil {
  92. panic(err)
  93. }
  94. n := new(int64)
  95. privVal := &PrivValidator{
  96. Address: address,
  97. PubKey: ReadBinary(PubKeyEd25519{}, bytes.NewReader(pubKeyBytes), n, &err).(PubKeyEd25519),
  98. PrivKey: ReadBinary(PrivKeyEd25519{}, bytes.NewReader(privKeyBytes), n, &err).(PrivKeyEd25519),
  99. LastHeight: privValJSON.LastHeight,
  100. LastRound: privValJSON.LastRound,
  101. LastStep: privValJSON.LastStep,
  102. }
  103. if err != nil {
  104. panic(err)
  105. }
  106. return privVal
  107. }
  108. func (privVal *PrivValidator) Save() {
  109. privValJSON := PrivValidatorJSON{
  110. Address: base64.StdEncoding.EncodeToString(privVal.Address),
  111. PubKey: base64.StdEncoding.EncodeToString(BinaryBytes(privVal.PubKey)),
  112. PrivKey: base64.StdEncoding.EncodeToString(BinaryBytes(privVal.PrivKey)),
  113. LastHeight: privVal.LastHeight,
  114. LastRound: privVal.LastRound,
  115. LastStep: privVal.LastStep,
  116. }
  117. privValJSONBytes, err := json.Marshal(privValJSON)
  118. if err != nil {
  119. panic(err)
  120. }
  121. err = ioutil.WriteFile(privVal.filename, privValJSONBytes, 0700)
  122. if err != nil {
  123. panic(err)
  124. }
  125. }
  126. // TODO: test
  127. func (privVal *PrivValidator) SignVote(vote *Vote) SignatureEd25519 {
  128. // If height regression, panic
  129. if privVal.LastHeight > vote.Height {
  130. panic("Height regression in SignVote")
  131. }
  132. // More cases for when the height matches
  133. if privVal.LastHeight == vote.Height {
  134. // If attempting any sign after commit, panic
  135. if privVal.LastStep == stepCommit {
  136. panic("SignVote on matching height after a commit")
  137. }
  138. // If round regression, panic
  139. if privVal.LastRound > vote.Round {
  140. panic("Round regression in SignVote")
  141. }
  142. // If step regression, panic
  143. if privVal.LastRound == vote.Round && privVal.LastStep > voteToStep(vote) {
  144. panic("Step regression in SignVote")
  145. }
  146. }
  147. // Persist height/round/step
  148. privVal.LastHeight = vote.Height
  149. privVal.LastRound = vote.Round
  150. privVal.LastStep = voteToStep(vote)
  151. privVal.Save()
  152. // Sign
  153. return privVal.SignVoteUnsafe(vote)
  154. }
  155. func (privVal *PrivValidator) SignVoteUnsafe(vote *Vote) SignatureEd25519 {
  156. return privVal.PrivKey.Sign(SignBytes(vote)).(SignatureEd25519)
  157. }
  158. func (privVal *PrivValidator) SignProposal(proposal *Proposal) SignatureEd25519 {
  159. if privVal.LastHeight < proposal.Height ||
  160. privVal.LastHeight == proposal.Height && privVal.LastRound < proposal.Round ||
  161. privVal.LastHeight == 0 && privVal.LastRound == 0 && privVal.LastStep == stepNone {
  162. // Persist height/round/step
  163. privVal.LastHeight = proposal.Height
  164. privVal.LastRound = proposal.Round
  165. privVal.LastStep = stepPropose
  166. privVal.Save()
  167. // Sign
  168. return privVal.PrivKey.Sign(SignBytes(proposal)).(SignatureEd25519)
  169. } else {
  170. panic(fmt.Sprintf("Attempt of duplicate signing of proposal: Height %v, Round %v", proposal.Height, proposal.Round))
  171. }
  172. }
  173. func (privVal *PrivValidator) SignRebondTx(rebondTx *RebondTx) SignatureEd25519 {
  174. if privVal.LastHeight < rebondTx.Height {
  175. // Persist height/round/step
  176. privVal.LastHeight = rebondTx.Height
  177. privVal.LastRound = math.MaxUint64 // We can't do anything else for this rebondTx.Height.
  178. privVal.LastStep = math.MaxUint8
  179. privVal.Save()
  180. // Sign
  181. return privVal.PrivKey.Sign(SignBytes(rebondTx)).(SignatureEd25519)
  182. } else {
  183. panic(fmt.Sprintf("Attempt of duplicate signing of rebondTx: Height %v", rebondTx.Height))
  184. }
  185. }
  186. func (privVal *PrivValidator) String() string {
  187. return fmt.Sprintf("PrivValidator{%X LH:%v, LR:%v, LS:%v}", privVal.Address, privVal.LastHeight, privVal.LastRound, privVal.LastStep)
  188. }