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.

139 lines
3.3 KiB

10 years ago
10 years ago
10 years ago
  1. package state
  2. import (
  3. "bytes"
  4. "io/ioutil"
  5. "sync"
  6. "time"
  7. . "github.com/tendermint/go-common"
  8. dbm "github.com/tendermint/go-db"
  9. "github.com/tendermint/go-wire"
  10. "github.com/tendermint/tendermint/events"
  11. "github.com/tendermint/tendermint/types"
  12. )
  13. var (
  14. stateKey = []byte("stateKey")
  15. )
  16. //-----------------------------------------------------------------------------
  17. // NOTE: not goroutine-safe.
  18. type State struct {
  19. mtx sync.Mutex
  20. db dbm.DB
  21. GenesisDoc *types.GenesisDoc
  22. ChainID string
  23. LastBlockHeight int
  24. LastBlockHash []byte
  25. LastBlockParts types.PartSetHeader
  26. LastBlockTime time.Time
  27. Validators *types.ValidatorSet
  28. LastValidators *types.ValidatorSet
  29. LastAppHash []byte
  30. evc events.Fireable // typically an events.EventCache
  31. }
  32. func LoadState(db dbm.DB) *State {
  33. s := &State{db: db}
  34. buf := db.Get(stateKey)
  35. if len(buf) == 0 {
  36. return nil
  37. } else {
  38. r, n, err := bytes.NewReader(buf), new(int), new(error)
  39. wire.ReadBinaryPtr(&s, r, 0, n, err)
  40. if *err != nil {
  41. // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
  42. Exit(Fmt("Data has been corrupted or its spec has changed: %v\n", *err))
  43. }
  44. // TODO: ensure that buf is completely read.
  45. }
  46. return s
  47. }
  48. func (s *State) Copy() *State {
  49. return &State{
  50. db: s.db,
  51. GenesisDoc: s.GenesisDoc,
  52. ChainID: s.ChainID,
  53. LastBlockHeight: s.LastBlockHeight,
  54. LastBlockHash: s.LastBlockHash,
  55. LastBlockParts: s.LastBlockParts,
  56. LastBlockTime: s.LastBlockTime,
  57. Validators: s.Validators.Copy(),
  58. LastValidators: s.LastValidators.Copy(),
  59. LastAppHash: s.LastAppHash,
  60. evc: nil,
  61. }
  62. }
  63. func (s *State) Save() {
  64. s.mtx.Lock()
  65. defer s.mtx.Unlock()
  66. buf, n, err := new(bytes.Buffer), new(int), new(error)
  67. wire.WriteBinary(s, buf, n, err)
  68. if *err != nil {
  69. PanicCrisis(*err)
  70. }
  71. s.db.Set(stateKey, buf.Bytes())
  72. }
  73. // Implements events.Eventable. Typically uses events.EventCache
  74. func (s *State) SetFireable(evc events.Fireable) {
  75. s.mtx.Lock()
  76. defer s.mtx.Unlock()
  77. s.evc = evc
  78. }
  79. //-----------------------------------------------------------------------------
  80. // Genesis
  81. func MakeGenesisStateFromFile(db dbm.DB, genDocFile string) *State {
  82. genDocJSON, err := ioutil.ReadFile(genDocFile)
  83. if err != nil {
  84. Exit(Fmt("Couldn't read GenesisDoc file: %v", err))
  85. }
  86. genDoc := types.GenesisDocFromJSON(genDocJSON)
  87. return MakeGenesisState(db, genDoc)
  88. }
  89. func MakeGenesisState(db dbm.DB, genDoc *types.GenesisDoc) *State {
  90. if len(genDoc.Validators) == 0 {
  91. Exit(Fmt("The genesis file has no validators"))
  92. }
  93. if genDoc.GenesisTime.IsZero() {
  94. genDoc.GenesisTime = time.Now()
  95. }
  96. // Make validators slice
  97. validators := make([]*types.Validator, len(genDoc.Validators))
  98. for i, val := range genDoc.Validators {
  99. pubKey := val.PubKey
  100. address := pubKey.Address()
  101. // Make validator
  102. validators[i] = &types.Validator{
  103. Address: address,
  104. PubKey: pubKey,
  105. VotingPower: val.Amount,
  106. }
  107. }
  108. return &State{
  109. db: db,
  110. GenesisDoc: genDoc,
  111. ChainID: genDoc.ChainID,
  112. LastBlockHeight: 0,
  113. LastBlockHash: nil,
  114. LastBlockParts: types.PartSetHeader{},
  115. LastBlockTime: genDoc.GenesisTime,
  116. Validators: types.NewValidatorSet(validators),
  117. LastValidators: types.NewValidatorSet(nil),
  118. LastAppHash: genDoc.AppHash,
  119. }
  120. }