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.

124 lines
3.0 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/types"
  11. )
  12. var (
  13. stateKey = []byte("stateKey")
  14. )
  15. //-----------------------------------------------------------------------------
  16. // NOTE: not goroutine-safe.
  17. type State struct {
  18. mtx sync.Mutex
  19. db dbm.DB
  20. GenesisDoc *types.GenesisDoc
  21. ChainID string
  22. LastBlockHeight int // Genesis state has this set to 0. So, Block(H=0) does not exist.
  23. LastBlockID types.BlockID
  24. LastBlockTime time.Time
  25. Validators *types.ValidatorSet
  26. LastValidators *types.ValidatorSet
  27. AppHash []byte
  28. }
  29. func LoadState(db dbm.DB) *State {
  30. s := &State{db: db}
  31. buf := db.Get(stateKey)
  32. if len(buf) == 0 {
  33. return nil
  34. } else {
  35. r, n, err := bytes.NewReader(buf), new(int), new(error)
  36. wire.ReadBinaryPtr(&s, r, 0, n, err)
  37. if *err != nil {
  38. // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
  39. Exit(Fmt("Data has been corrupted or its spec has changed: %v\n", *err))
  40. }
  41. // TODO: ensure that buf is completely read.
  42. }
  43. return s
  44. }
  45. func (s *State) Copy() *State {
  46. return &State{
  47. db: s.db,
  48. GenesisDoc: s.GenesisDoc,
  49. ChainID: s.ChainID,
  50. LastBlockHeight: s.LastBlockHeight,
  51. LastBlockID: s.LastBlockID,
  52. LastBlockTime: s.LastBlockTime,
  53. Validators: s.Validators.Copy(),
  54. LastValidators: s.LastValidators.Copy(),
  55. AppHash: s.AppHash,
  56. }
  57. }
  58. func (s *State) Save() {
  59. s.mtx.Lock()
  60. defer s.mtx.Unlock()
  61. buf, n, err := new(bytes.Buffer), new(int), new(error)
  62. wire.WriteBinary(s, buf, n, err)
  63. if *err != nil {
  64. PanicCrisis(*err)
  65. }
  66. s.db.Set(stateKey, buf.Bytes())
  67. }
  68. //-----------------------------------------------------------------------------
  69. // Genesis
  70. func MakeGenesisStateFromFile(db dbm.DB, genDocFile string) *State {
  71. genDocJSON, err := ioutil.ReadFile(genDocFile)
  72. if err != nil {
  73. Exit(Fmt("Couldn't read GenesisDoc file: %v", err))
  74. }
  75. genDoc := types.GenesisDocFromJSON(genDocJSON)
  76. return MakeGenesisState(db, genDoc)
  77. }
  78. func MakeGenesisState(db dbm.DB, genDoc *types.GenesisDoc) *State {
  79. if len(genDoc.Validators) == 0 {
  80. Exit(Fmt("The genesis file has no validators"))
  81. }
  82. if genDoc.GenesisTime.IsZero() {
  83. genDoc.GenesisTime = time.Now()
  84. }
  85. // Make validators slice
  86. validators := make([]*types.Validator, len(genDoc.Validators))
  87. for i, val := range genDoc.Validators {
  88. pubKey := val.PubKey
  89. address := pubKey.Address()
  90. // Make validator
  91. validators[i] = &types.Validator{
  92. Address: address,
  93. PubKey: pubKey,
  94. VotingPower: val.Amount,
  95. }
  96. }
  97. return &State{
  98. db: db,
  99. GenesisDoc: genDoc,
  100. ChainID: genDoc.ChainID,
  101. LastBlockHeight: 0,
  102. LastBlockID: types.BlockID{},
  103. LastBlockTime: genDoc.GenesisTime,
  104. Validators: types.NewValidatorSet(validators),
  105. LastValidators: types.NewValidatorSet(nil),
  106. AppHash: genDoc.AppHash,
  107. }
  108. }