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.

268 lines
7.2 KiB

8 years ago
10 years ago
8 years ago
10 years ago
10 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. package state
  2. import (
  3. "bytes"
  4. "io/ioutil"
  5. "sync"
  6. "time"
  7. "github.com/spf13/viper"
  8. abci "github.com/tendermint/abci/types"
  9. cmn "github.com/tendermint/tmlibs/common"
  10. dbm "github.com/tendermint/tmlibs/db"
  11. "github.com/tendermint/go-wire"
  12. "github.com/tendermint/tendermint/state/txindex"
  13. "github.com/tendermint/tendermint/state/txindex/null"
  14. "github.com/tendermint/tendermint/types"
  15. )
  16. var (
  17. stateKey = []byte("stateKey")
  18. abciResponsesKey = []byte("abciResponsesKey")
  19. )
  20. //-----------------------------------------------------------------------------
  21. // NOTE: not goroutine-safe.
  22. type State struct {
  23. // mtx for writing to db
  24. mtx sync.Mutex
  25. db dbm.DB
  26. // should not change
  27. GenesisDoc *types.GenesisDoc
  28. ChainID string
  29. // updated at end of SetBlockAndValidators
  30. LastBlockHeight int // Genesis state has this set to 0. So, Block(H=0) does not exist.
  31. LastBlockID types.BlockID
  32. LastBlockTime time.Time
  33. Validators *types.ValidatorSet
  34. LastValidators *types.ValidatorSet // block.LastCommit validated against this
  35. // AppHash is updated after Commit
  36. AppHash []byte
  37. TxIndexer txindex.TxIndexer `json:"-"` // Transaction indexer.
  38. // Intermediate results from processing
  39. // Persisted separately from the state
  40. abciResponses *ABCIResponses
  41. }
  42. func LoadState(db dbm.DB) *State {
  43. return loadState(db, stateKey)
  44. }
  45. func loadState(db dbm.DB, key []byte) *State {
  46. s := &State{db: db, TxIndexer: &null.TxIndex{}}
  47. buf := db.Get(key)
  48. if len(buf) == 0 {
  49. return nil
  50. } else {
  51. r, n, err := bytes.NewReader(buf), new(int), new(error)
  52. wire.ReadBinaryPtr(&s, r, 0, n, err)
  53. if *err != nil {
  54. // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
  55. cmn.Exit(cmn.Fmt("LoadState: Data has been corrupted or its spec has changed: %v\n", *err))
  56. }
  57. // TODO: ensure that buf is completely read.
  58. }
  59. return s
  60. }
  61. func (s *State) Copy() *State {
  62. return &State{
  63. db: s.db,
  64. GenesisDoc: s.GenesisDoc,
  65. ChainID: s.ChainID,
  66. LastBlockHeight: s.LastBlockHeight,
  67. LastBlockID: s.LastBlockID,
  68. LastBlockTime: s.LastBlockTime,
  69. Validators: s.Validators.Copy(),
  70. LastValidators: s.LastValidators.Copy(),
  71. AppHash: s.AppHash,
  72. TxIndexer: s.TxIndexer, // pointer here, not value
  73. }
  74. }
  75. func (s *State) Save() {
  76. s.mtx.Lock()
  77. defer s.mtx.Unlock()
  78. s.db.SetSync(stateKey, s.Bytes())
  79. }
  80. // Sets the ABCIResponses in the state and writes them to disk
  81. // in case we crash after app.Commit and before s.Save()
  82. func (s *State) SaveABCIResponses(abciResponses *ABCIResponses) {
  83. // save the validators to the db
  84. s.db.SetSync(abciResponsesKey, abciResponses.Bytes())
  85. }
  86. func (s *State) LoadABCIResponses() *ABCIResponses {
  87. abciResponses := new(ABCIResponses)
  88. buf := s.db.Get(abciResponsesKey)
  89. if len(buf) != 0 {
  90. r, n, err := bytes.NewReader(buf), new(int), new(error)
  91. wire.ReadBinaryPtr(abciResponses, r, 0, n, err)
  92. if *err != nil {
  93. // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
  94. cmn.Exit(cmn.Fmt("LoadABCIResponses: Data has been corrupted or its spec has changed: %v\n", *err))
  95. }
  96. // TODO: ensure that buf is completely read.
  97. }
  98. return abciResponses
  99. }
  100. func (s *State) Equals(s2 *State) bool {
  101. return bytes.Equal(s.Bytes(), s2.Bytes())
  102. }
  103. func (s *State) Bytes() []byte {
  104. buf, n, err := new(bytes.Buffer), new(int), new(error)
  105. wire.WriteBinary(s, buf, n, err)
  106. if *err != nil {
  107. cmn.PanicCrisis(*err)
  108. }
  109. return buf.Bytes()
  110. }
  111. // Mutate state variables to match block and validators
  112. // after running EndBlock
  113. func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader types.PartSetHeader, abciResponses *ABCIResponses) {
  114. // copy the valset so we can apply changes from EndBlock
  115. // and update s.LastValidators and s.Validators
  116. prevValSet := s.Validators.Copy()
  117. nextValSet := prevValSet.Copy()
  118. // update the validator set with the latest abciResponses
  119. err := updateValidators(nextValSet, abciResponses.EndBlock.Diffs)
  120. if err != nil {
  121. log.Warn("Error changing validator set", "error", err)
  122. // TODO: err or carry on?
  123. }
  124. // Update validator accums and set state variables
  125. nextValSet.IncrementAccum(1)
  126. s.setBlockAndValidators(header.Height,
  127. types.BlockID{header.Hash(), blockPartsHeader}, header.Time,
  128. prevValSet, nextValSet)
  129. }
  130. func (s *State) setBlockAndValidators(
  131. height int, blockID types.BlockID, blockTime time.Time,
  132. prevValSet, nextValSet *types.ValidatorSet) {
  133. s.LastBlockHeight = height
  134. s.LastBlockID = blockID
  135. s.LastBlockTime = blockTime
  136. s.Validators = nextValSet
  137. s.LastValidators = prevValSet
  138. }
  139. func (s *State) GetValidators() (*types.ValidatorSet, *types.ValidatorSet) {
  140. return s.LastValidators, s.Validators
  141. }
  142. // Load the most recent state from "state" db,
  143. // or create a new one (and save) from genesis.
  144. func GetState(config *viper.Viper, stateDB dbm.DB) *State {
  145. state := LoadState(stateDB)
  146. if state == nil {
  147. state = MakeGenesisStateFromFile(stateDB, config.GetString("genesis_file"))
  148. state.Save()
  149. }
  150. return state
  151. }
  152. //--------------------------------------------------
  153. // ABCIResponses holds intermediate state during block processing
  154. type ABCIResponses struct {
  155. Height int
  156. DeliverTx []*abci.ResponseDeliverTx
  157. EndBlock abci.ResponseEndBlock
  158. txs types.Txs // reference for indexing results by hash
  159. }
  160. func NewABCIResponses(block *types.Block) *ABCIResponses {
  161. return &ABCIResponses{
  162. Height: block.Height,
  163. DeliverTx: make([]*abci.ResponseDeliverTx, block.NumTxs),
  164. txs: block.Data.Txs,
  165. }
  166. }
  167. // Serialize the ABCIResponse
  168. func (a *ABCIResponses) Bytes() []byte {
  169. buf, n, err := new(bytes.Buffer), new(int), new(error)
  170. wire.WriteBinary(*a, buf, n, err)
  171. if *err != nil {
  172. cmn.PanicCrisis(*err)
  173. }
  174. return buf.Bytes()
  175. }
  176. //-----------------------------------------------------------------------------
  177. // Genesis
  178. // MakeGenesisStateFromFile reads and unmarshals state from the given file.
  179. //
  180. // Used during replay and in tests.
  181. func MakeGenesisStateFromFile(db dbm.DB, genDocFile string) *State {
  182. genDocJSON, err := ioutil.ReadFile(genDocFile)
  183. if err != nil {
  184. cmn.Exit(cmn.Fmt("Couldn't read GenesisDoc file: %v", err))
  185. }
  186. genDoc, err := types.GenesisDocFromJSON(genDocJSON)
  187. if err != nil {
  188. cmn.Exit(cmn.Fmt("Error reading GenesisDoc: %v", err))
  189. }
  190. return MakeGenesisState(db, genDoc)
  191. }
  192. // MakeGenesisState creates state from types.GenesisDoc.
  193. //
  194. // Used in tests.
  195. func MakeGenesisState(db dbm.DB, genDoc *types.GenesisDoc) *State {
  196. if len(genDoc.Validators) == 0 {
  197. cmn.Exit(cmn.Fmt("The genesis file has no validators"))
  198. }
  199. if genDoc.GenesisTime.IsZero() {
  200. genDoc.GenesisTime = time.Now()
  201. }
  202. // Make validators slice
  203. validators := make([]*types.Validator, len(genDoc.Validators))
  204. for i, val := range genDoc.Validators {
  205. pubKey := val.PubKey
  206. address := pubKey.Address()
  207. // Make validator
  208. validators[i] = &types.Validator{
  209. Address: address,
  210. PubKey: pubKey,
  211. VotingPower: val.Amount,
  212. }
  213. }
  214. return &State{
  215. db: db,
  216. GenesisDoc: genDoc,
  217. ChainID: genDoc.ChainID,
  218. LastBlockHeight: 0,
  219. LastBlockID: types.BlockID{},
  220. LastBlockTime: genDoc.GenesisTime,
  221. Validators: types.NewValidatorSet(validators),
  222. LastValidators: types.NewValidatorSet(nil),
  223. AppHash: genDoc.AppHash,
  224. TxIndexer: &null.TxIndex{}, // we do not need indexer during replay and in tests
  225. }
  226. }