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.

138 lines
3.2 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.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. func (s *State) SetEventCache(evc *events.EventCache) {
  74. s.mtx.Lock()
  75. defer s.mtx.Unlock()
  76. s.evc = evc
  77. }
  78. //-----------------------------------------------------------------------------
  79. // Genesis
  80. func MakeGenesisStateFromFile(db dbm.DB, genDocFile string) *State {
  81. genDocJSON, err := ioutil.ReadFile(genDocFile)
  82. if err != nil {
  83. Exit(Fmt("Couldn't read GenesisDoc file: %v", err))
  84. }
  85. genDoc := types.GenesisDocFromJSON(genDocJSON)
  86. return MakeGenesisState(db, genDoc)
  87. }
  88. func MakeGenesisState(db dbm.DB, genDoc *types.GenesisDoc) *State {
  89. if len(genDoc.Validators) == 0 {
  90. Exit(Fmt("The genesis file has no validators"))
  91. }
  92. if genDoc.GenesisTime.IsZero() {
  93. genDoc.GenesisTime = time.Now()
  94. }
  95. // Make validators slice
  96. validators := make([]*types.Validator, len(genDoc.Validators))
  97. for i, val := range genDoc.Validators {
  98. pubKey := val.PubKey
  99. address := pubKey.Address()
  100. // Make validator
  101. validators[i] = &types.Validator{
  102. Address: address,
  103. PubKey: pubKey,
  104. VotingPower: val.Amount,
  105. }
  106. }
  107. return &State{
  108. db: db,
  109. GenesisDoc: genDoc,
  110. ChainID: genDoc.ChainID,
  111. LastBlockHeight: 0,
  112. LastBlockHash: nil,
  113. LastBlockParts: types.PartSetHeader{},
  114. LastBlockTime: genDoc.GenesisTime,
  115. Validators: types.NewValidatorSet(validators),
  116. LastValidators: types.NewValidatorSet(nil),
  117. LastAppHash: genDoc.AppHash,
  118. }
  119. }