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.

171 lines
4.6 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
  1. package proxy
  2. import (
  3. "bytes"
  4. "fmt"
  5. . "github.com/tendermint/go-common"
  6. cfg "github.com/tendermint/go-config"
  7. "github.com/tendermint/tendermint/types"
  8. )
  9. //-----------------------------
  10. // Tendermint's interface to the application consists of multiple connections
  11. type AppConns interface {
  12. Service
  13. Mempool() AppConnMempool
  14. Consensus() AppConnConsensus
  15. Query() AppConnQuery
  16. }
  17. func NewAppConns(config cfg.Config, clientCreator ClientCreator, state State, blockStore BlockStore) AppConns {
  18. return NewMultiAppConn(config, clientCreator, state, blockStore)
  19. }
  20. //-----------------------------
  21. // multiAppConn implements AppConns
  22. // a multiAppConn is made of a few appConns (mempool, consensus, query)
  23. // and manages their underlying tmsp clients, including the handshake
  24. // which ensures the app and tendermint are synced.
  25. // TODO: on app restart, clients must reboot together
  26. type multiAppConn struct {
  27. BaseService
  28. config cfg.Config
  29. state State
  30. blockStore BlockStore
  31. mempoolConn *appConnMempool
  32. consensusConn *appConnConsensus
  33. queryConn *appConnQuery
  34. clientCreator ClientCreator
  35. }
  36. // Make all necessary tmsp connections to the application
  37. func NewMultiAppConn(config cfg.Config, clientCreator ClientCreator, state State, blockStore BlockStore) *multiAppConn {
  38. multiAppConn := &multiAppConn{
  39. config: config,
  40. state: state,
  41. blockStore: blockStore,
  42. clientCreator: clientCreator,
  43. }
  44. multiAppConn.BaseService = *NewBaseService(log, "multiAppConn", multiAppConn)
  45. return multiAppConn
  46. }
  47. // Returns the mempool connection
  48. func (app *multiAppConn) Mempool() AppConnMempool {
  49. return app.mempoolConn
  50. }
  51. // Returns the consensus Connection
  52. func (app *multiAppConn) Consensus() AppConnConsensus {
  53. return app.consensusConn
  54. }
  55. // Returns the query Connection
  56. func (app *multiAppConn) Query() AppConnQuery {
  57. return app.queryConn
  58. }
  59. func (app *multiAppConn) OnStart() error {
  60. app.BaseService.OnStart()
  61. // query connection
  62. querycli, err := app.clientCreator.NewTMSPClient()
  63. if err != nil {
  64. return err
  65. }
  66. app.queryConn = NewAppConnQuery(querycli)
  67. // mempool connection
  68. memcli, err := app.clientCreator.NewTMSPClient()
  69. if err != nil {
  70. return err
  71. }
  72. app.mempoolConn = NewAppConnMempool(memcli)
  73. // consensus connection
  74. concli, err := app.clientCreator.NewTMSPClient()
  75. if err != nil {
  76. return err
  77. }
  78. app.consensusConn = NewAppConnConsensus(concli)
  79. // ensure app is synced to the latest state
  80. return app.Handshake()
  81. }
  82. // TODO: retry the handshake once if it fails the first time
  83. // ... let Info take an argument determining its behaviour
  84. func (app *multiAppConn) Handshake() error {
  85. // handshake is done via info request on the query conn
  86. res, tmspInfo, blockInfo, configInfo := app.queryConn.InfoSync()
  87. if res.IsErr() {
  88. return fmt.Errorf("Error calling Info. Code: %v; Data: %X; Log: %s", res.Code, res.Data, res.Log)
  89. }
  90. if blockInfo == nil {
  91. log.Warn("blockInfo is nil, aborting handshake")
  92. return nil
  93. }
  94. log.Notice("TMSP Handshake", "height", blockInfo.BlockHeight, "block_hash", blockInfo.BlockHash, "app_hash", blockInfo.AppHash)
  95. // TODO: check overflow or change pb to int32
  96. blockHeight := int(blockInfo.BlockHeight)
  97. blockHash := blockInfo.BlockHash
  98. appHash := blockInfo.AppHash
  99. if tmspInfo != nil {
  100. // TODO: check tmsp version (or do this in the tmspcli?)
  101. _ = tmspInfo
  102. }
  103. // last block (nil if we starting from 0)
  104. var header *types.Header
  105. var partsHeader types.PartSetHeader
  106. // replay all blocks after blockHeight
  107. // if blockHeight == 0, we will replay everything
  108. if blockHeight != 0 {
  109. blockMeta := app.blockStore.LoadBlockMeta(blockHeight)
  110. if blockMeta == nil {
  111. return fmt.Errorf("Handshake error. Could not find block #%d", blockHeight)
  112. }
  113. // check block hash
  114. if !bytes.Equal(blockMeta.Hash, blockHash) {
  115. return fmt.Errorf("Handshake error. Block hash at height %d does not match. Got %X, expected %X", blockHeight, blockHash, blockMeta.Hash)
  116. }
  117. // NOTE: app hash should be in the next block ...
  118. // check app hash
  119. /*if !bytes.Equal(blockMeta.Header.AppHash, appHash) {
  120. return fmt.Errorf("Handshake error. App hash at height %d does not match. Got %X, expected %X", blockHeight, appHash, blockMeta.Header.AppHash)
  121. }*/
  122. header = blockMeta.Header
  123. partsHeader = blockMeta.PartsHeader
  124. }
  125. if configInfo != nil {
  126. // TODO: set config info
  127. _ = configInfo
  128. }
  129. // replay blocks up to the latest in the blockstore
  130. err := app.state.ReplayBlocks(appHash, header, partsHeader, app.consensusConn, app.blockStore)
  131. if err != nil {
  132. return fmt.Errorf("Error on replay: %v", err)
  133. }
  134. // TODO: (on restart) replay mempool
  135. return nil
  136. }