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.

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