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.

290 lines
8.4 KiB

8 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
8 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
8 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
8 years ago
8 years ago
8 years ago
8 years ago
  1. package state
  2. import (
  3. "errors"
  4. "github.com/ebuchman/fail-test"
  5. abci "github.com/tendermint/abci/types"
  6. . "github.com/tendermint/go-common"
  7. "github.com/tendermint/go-crypto"
  8. "github.com/tendermint/tendermint/proxy"
  9. "github.com/tendermint/tendermint/types"
  10. )
  11. //--------------------------------------------------
  12. // Execute the block
  13. // Execute the block to mutate State.
  14. // Validates block and then executes Data.Txs in the block.
  15. func (s *State) ExecBlock(eventCache types.Fireable, proxyAppConn proxy.AppConnConsensus, block *types.Block, blockPartsHeader types.PartSetHeader) error {
  16. // Validate the block.
  17. if err := s.validateBlock(block); err != nil {
  18. return ErrInvalidBlock(err)
  19. }
  20. // compute bitarray of validators that signed
  21. signed := commitBitArrayFromBlock(block)
  22. _ = signed // TODO send on begin block
  23. // copy the valset
  24. valSet := s.Validators.Copy()
  25. nextValSet := valSet.Copy()
  26. // Execute the block txs
  27. changedValidators, err := execBlockOnProxyApp(eventCache, proxyAppConn, block)
  28. if err != nil {
  29. // There was some error in proxyApp
  30. // TODO Report error and wait for proxyApp to be available.
  31. return ErrProxyAppConn(err)
  32. }
  33. // update the validator set
  34. err = updateValidators(nextValSet, changedValidators)
  35. if err != nil {
  36. log.Warn("Error changing validator set", "error", err)
  37. // TODO: err or carry on?
  38. }
  39. // All good!
  40. // Update validator accums and set state variables
  41. nextValSet.IncrementAccum(1)
  42. s.SetBlockAndValidators(block.Header, blockPartsHeader, valSet, nextValSet)
  43. fail.Fail() // XXX
  44. return nil
  45. }
  46. // Executes block's transactions on proxyAppConn.
  47. // Returns a list of updates to the validator set
  48. // TODO: Generate a bitmap or otherwise store tx validity in state.
  49. func execBlockOnProxyApp(eventCache types.Fireable, proxyAppConn proxy.AppConnConsensus, block *types.Block) ([]*abci.Validator, error) {
  50. var validTxs, invalidTxs = 0, 0
  51. // Execute transactions and get hash
  52. proxyCb := func(req *abci.Request, res *abci.Response) {
  53. switch r := res.Value.(type) {
  54. case *abci.Response_DeliverTx:
  55. // TODO: make use of res.Log
  56. // TODO: make use of this info
  57. // Blocks may include invalid txs.
  58. // reqDeliverTx := req.(abci.RequestDeliverTx)
  59. txError := ""
  60. apTx := r.DeliverTx
  61. if apTx.Code == abci.CodeType_OK {
  62. validTxs += 1
  63. } else {
  64. log.Debug("Invalid tx", "code", r.DeliverTx.Code, "log", r.DeliverTx.Log)
  65. invalidTxs += 1
  66. txError = apTx.Code.String()
  67. }
  68. // NOTE: if we count we can access the tx from the block instead of
  69. // pulling it from the req
  70. event := types.EventDataTx{
  71. Tx: req.GetDeliverTx().Tx,
  72. Data: apTx.Data,
  73. Code: apTx.Code,
  74. Log: apTx.Log,
  75. Error: txError,
  76. }
  77. types.FireEventTx(eventCache, event)
  78. }
  79. }
  80. proxyAppConn.SetResponseCallback(proxyCb)
  81. // Begin block
  82. err := proxyAppConn.BeginBlockSync(block.Hash(), types.TM2PB.Header(block.Header))
  83. if err != nil {
  84. log.Warn("Error in proxyAppConn.BeginBlock", "error", err)
  85. return nil, err
  86. }
  87. fail.Fail() // XXX
  88. // Run txs of block
  89. for _, tx := range block.Txs {
  90. fail.FailRand(len(block.Txs)) // XXX
  91. proxyAppConn.DeliverTxAsync(tx)
  92. if err := proxyAppConn.Error(); err != nil {
  93. return nil, err
  94. }
  95. }
  96. fail.Fail() // XXX
  97. // End block
  98. respEndBlock, err := proxyAppConn.EndBlockSync(uint64(block.Height))
  99. if err != nil {
  100. log.Warn("Error in proxyAppConn.EndBlock", "error", err)
  101. return nil, err
  102. }
  103. fail.Fail() // XXX
  104. log.Info("Executed block", "height", block.Height, "valid txs", validTxs, "invalid txs", invalidTxs)
  105. if len(respEndBlock.Diffs) > 0 {
  106. log.Info("Update to validator set", "updates", abci.ValidatorsString(respEndBlock.Diffs))
  107. }
  108. return respEndBlock.Diffs, nil
  109. }
  110. func updateValidators(validators *types.ValidatorSet, changedValidators []*abci.Validator) error {
  111. // TODO: prevent change of 1/3+ at once
  112. for _, v := range changedValidators {
  113. pubkey, err := crypto.PubKeyFromBytes(v.PubKey) // NOTE: expects go-wire encoded pubkey
  114. if err != nil {
  115. return err
  116. }
  117. address := pubkey.Address()
  118. power := int64(v.Power)
  119. // mind the overflow from uint64
  120. if power < 0 {
  121. return errors.New(Fmt("Power (%d) overflows int64", v.Power))
  122. }
  123. _, val := validators.GetByAddress(address)
  124. if val == nil {
  125. // add val
  126. added := validators.Add(types.NewValidator(pubkey, power))
  127. if !added {
  128. return errors.New(Fmt("Failed to add new validator %X with voting power %d", address, power))
  129. }
  130. } else if v.Power == 0 {
  131. // remove val
  132. _, removed := validators.Remove(address)
  133. if !removed {
  134. return errors.New(Fmt("Failed to remove validator %X)"))
  135. }
  136. } else {
  137. // update val
  138. val.VotingPower = power
  139. updated := validators.Update(val)
  140. if !updated {
  141. return errors.New(Fmt("Failed to update validator %X with voting power %d", address, power))
  142. }
  143. }
  144. }
  145. return nil
  146. }
  147. // return a bit array of validators that signed the last commit
  148. // NOTE: assumes commits have already been authenticated
  149. func commitBitArrayFromBlock(block *types.Block) *BitArray {
  150. signed := NewBitArray(len(block.LastCommit.Precommits))
  151. for i, precommit := range block.LastCommit.Precommits {
  152. if precommit != nil {
  153. signed.SetIndex(i, true) // val_.LastCommitHeight = block.Height - 1
  154. }
  155. }
  156. return signed
  157. }
  158. //-----------------------------------------------------
  159. // Validate block
  160. func (s *State) ValidateBlock(block *types.Block) error {
  161. return s.validateBlock(block)
  162. }
  163. func (s *State) validateBlock(block *types.Block) error {
  164. // Basic block validation.
  165. err := block.ValidateBasic(s.ChainID, s.LastBlockHeight, s.LastBlockID, s.LastBlockTime, s.AppHash)
  166. if err != nil {
  167. return err
  168. }
  169. // Validate block LastCommit.
  170. if block.Height == 1 {
  171. if len(block.LastCommit.Precommits) != 0 {
  172. return errors.New("Block at height 1 (first block) should have no LastCommit precommits")
  173. }
  174. } else {
  175. if len(block.LastCommit.Precommits) != s.LastValidators.Size() {
  176. return errors.New(Fmt("Invalid block commit size. Expected %v, got %v",
  177. s.LastValidators.Size(), len(block.LastCommit.Precommits)))
  178. }
  179. err := s.LastValidators.VerifyCommit(
  180. s.ChainID, s.LastBlockID, block.Height-1, block.LastCommit)
  181. if err != nil {
  182. return err
  183. }
  184. }
  185. return nil
  186. }
  187. //-----------------------------------------------------------------------------
  188. // ApplyBlock executes the block, then commits and updates the mempool atomically
  189. // Execute and commit block against app, save block and state
  190. func (s *State) ApplyBlock(eventCache types.Fireable, proxyAppConn proxy.AppConnConsensus,
  191. block *types.Block, partsHeader types.PartSetHeader, mempool types.Mempool) error {
  192. // Run the block on the State:
  193. // + update validator sets
  194. // + run txs on the proxyAppConn
  195. err := s.ExecBlock(eventCache, proxyAppConn, block, partsHeader)
  196. if err != nil {
  197. return errors.New(Fmt("Exec failed for application: %v", err))
  198. }
  199. // lock mempool, commit state, update mempoool
  200. err = s.CommitStateUpdateMempool(proxyAppConn, block, mempool)
  201. if err != nil {
  202. return errors.New(Fmt("Commit failed for application: %v", err))
  203. }
  204. return nil
  205. }
  206. // mempool must be locked during commit and update
  207. // because state is typically reset on Commit and old txs must be replayed
  208. // against committed state before new txs are run in the mempool, lest they be invalid
  209. func (s *State) CommitStateUpdateMempool(proxyAppConn proxy.AppConnConsensus, block *types.Block, mempool types.Mempool) error {
  210. mempool.Lock()
  211. defer mempool.Unlock()
  212. // Commit block, get hash back
  213. res := proxyAppConn.CommitSync()
  214. if res.IsErr() {
  215. log.Warn("Error in proxyAppConn.CommitSync", "error", res)
  216. return res
  217. }
  218. if res.Log != "" {
  219. log.Debug("Commit.Log: " + res.Log)
  220. }
  221. log.Info("Committed state", "hash", res.Data)
  222. // Set the state's new AppHash
  223. s.AppHash = res.Data
  224. // Update mempool.
  225. mempool.Update(block.Height, block.Txs)
  226. return nil
  227. }
  228. // Apply and commit a block, but without all the state validation.
  229. // Returns the application root hash (result of abci.Commit)
  230. func ApplyBlock(appConnConsensus proxy.AppConnConsensus, block *types.Block) ([]byte, error) {
  231. var eventCache types.Fireable // nil
  232. _, err := execBlockOnProxyApp(eventCache, appConnConsensus, block)
  233. if err != nil {
  234. log.Warn("Error executing block on proxy app", "height", block.Height, "err", err)
  235. return nil, err
  236. }
  237. // Commit block, get hash back
  238. res := appConnConsensus.CommitSync()
  239. if res.IsErr() {
  240. log.Warn("Error in proxyAppConn.CommitSync", "error", res)
  241. return nil, res
  242. }
  243. if res.Log != "" {
  244. log.Info("Commit.Log: " + res.Log)
  245. }
  246. return res.Data, nil
  247. }