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.

230 lines
7.1 KiB

  1. package consensus
  2. import (
  3. "bufio"
  4. "bytes"
  5. "fmt"
  6. "io"
  7. "path/filepath"
  8. "testing"
  9. "time"
  10. db "github.com/tendermint/tm-db"
  11. "github.com/tendermint/tendermint/abci/example/kvstore"
  12. cfg "github.com/tendermint/tendermint/config"
  13. tmcon "github.com/tendermint/tendermint/consensus"
  14. "github.com/tendermint/tendermint/libs/log"
  15. tmrand "github.com/tendermint/tendermint/libs/rand"
  16. "github.com/tendermint/tendermint/privval"
  17. "github.com/tendermint/tendermint/proxy"
  18. sm "github.com/tendermint/tendermint/state"
  19. "github.com/tendermint/tendermint/store"
  20. "github.com/tendermint/tendermint/types"
  21. )
  22. // WALGenerateNBlocks generates a consensus WAL. It does this by spinning up a
  23. // stripped down version of node (proxy app, event bus, consensus state) with a
  24. // persistent kvstore application and special consensus wal instance
  25. // (byteBufferWAL) and waits until numBlocks are created.
  26. // If the node fails to produce given numBlocks, it returns an error.
  27. func WALGenerateNBlocks(t *testing.T, wr io.Writer, numBlocks int) (err error) {
  28. config := getConfig(t)
  29. app := kvstore.NewPersistentKVStoreApplication(filepath.Join(config.DBDir(), "wal_generator"))
  30. logger := log.TestingLogger().With("wal_generator", "wal_generator")
  31. logger.Info("generating WAL (last height msg excluded)", "numBlocks", numBlocks)
  32. // ///////////////////////////////////////////////////////////////////////////
  33. // COPY PASTE FROM node.go WITH A FEW MODIFICATIONS
  34. // NOTE: we can't import node package because of circular dependency.
  35. // NOTE: we don't do handshake so need to set state.Version.Consensus.App directly.
  36. privValidatorKeyFile := config.PrivValidatorKeyFile()
  37. privValidatorStateFile := config.PrivValidatorStateFile()
  38. privValidator := privval.LoadOrGenFilePV(privValidatorKeyFile, privValidatorStateFile)
  39. genDoc, err := types.GenesisDocFromFile(config.GenesisFile())
  40. if err != nil {
  41. return fmt.Errorf("failed to read genesis file: %w", err)
  42. }
  43. blockStoreDB := db.NewMemDB()
  44. stateDB := blockStoreDB
  45. stateStore := sm.NewStore(stateDB)
  46. state, err := sm.MakeGenesisState(genDoc)
  47. if err != nil {
  48. return fmt.Errorf("failed to make genesis state: %w", err)
  49. }
  50. state.Version.Consensus.App = kvstore.ProtocolVersion
  51. if err = stateStore.Save(state); err != nil {
  52. t.Error(err)
  53. }
  54. blockStore := store.NewBlockStore(blockStoreDB)
  55. proxyApp := proxy.NewAppConns(proxy.NewLocalClientCreator(app))
  56. proxyApp.SetLogger(logger.With("module", "proxy"))
  57. if err := proxyApp.Start(); err != nil {
  58. return fmt.Errorf("failed to start proxy app connections: %w", err)
  59. }
  60. t.Cleanup(func() {
  61. if err := proxyApp.Stop(); err != nil {
  62. t.Error(err)
  63. }
  64. })
  65. eventBus := types.NewEventBus()
  66. eventBus.SetLogger(logger.With("module", "events"))
  67. if err := eventBus.Start(); err != nil {
  68. return fmt.Errorf("failed to start event bus: %w", err)
  69. }
  70. t.Cleanup(func() {
  71. if err := eventBus.Stop(); err != nil {
  72. t.Error(err)
  73. }
  74. })
  75. mempool := emptyMempool{}
  76. evpool := sm.EmptyEvidencePool{}
  77. blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(), mempool, evpool)
  78. consensusState := NewState(config.Consensus, state.Copy(),
  79. blockExec, blockStore, mempool, evpool, map[int64]Misbehavior{})
  80. consensusState.SetLogger(logger)
  81. consensusState.SetEventBus(eventBus)
  82. if privValidator != nil {
  83. consensusState.SetPrivValidator(privValidator)
  84. }
  85. // END OF COPY PASTE
  86. // ///////////////////////////////////////////////////////////////////////////
  87. // set consensus wal to buffered WAL, which will write all incoming msgs to buffer
  88. numBlocksWritten := make(chan struct{})
  89. wal := newByteBufferWAL(logger, NewWALEncoder(wr), int64(numBlocks), numBlocksWritten)
  90. // see wal.go#103
  91. if err := wal.Write(tmcon.EndHeightMessage{Height: 0}); err != nil {
  92. t.Error(err)
  93. }
  94. consensusState.wal = wal
  95. if err := consensusState.Start(); err != nil {
  96. return fmt.Errorf("failed to start consensus state: %w", err)
  97. }
  98. select {
  99. case <-numBlocksWritten:
  100. if err := consensusState.Stop(); err != nil {
  101. t.Error(err)
  102. }
  103. return nil
  104. case <-time.After(1 * time.Minute):
  105. if err := consensusState.Stop(); err != nil {
  106. t.Error(err)
  107. }
  108. return fmt.Errorf("waited too long for tendermint to produce %d blocks (grep logs for `wal_generator`)", numBlocks)
  109. }
  110. }
  111. // WALWithNBlocks returns a WAL content with numBlocks.
  112. func WALWithNBlocks(t *testing.T, numBlocks int) (data []byte, err error) {
  113. var b bytes.Buffer
  114. wr := bufio.NewWriter(&b)
  115. if err := WALGenerateNBlocks(t, wr, numBlocks); err != nil {
  116. return []byte{}, err
  117. }
  118. wr.Flush()
  119. return b.Bytes(), nil
  120. }
  121. func randPort() int {
  122. // returns between base and base + spread
  123. base, spread := 20000, 20000
  124. return base + tmrand.Intn(spread)
  125. }
  126. func makeAddrs() (string, string, string) {
  127. start := randPort()
  128. return fmt.Sprintf("tcp://127.0.0.1:%d", start),
  129. fmt.Sprintf("tcp://127.0.0.1:%d", start+1),
  130. fmt.Sprintf("tcp://127.0.0.1:%d", start+2)
  131. }
  132. // getConfig returns a config for test cases
  133. func getConfig(t *testing.T) *cfg.Config {
  134. c := cfg.ResetTestRoot(t.Name())
  135. // and we use random ports to run in parallel
  136. tm, rpc, grpc := makeAddrs()
  137. c.P2P.ListenAddress = tm
  138. c.RPC.ListenAddress = rpc
  139. c.RPC.GRPCListenAddress = grpc
  140. return c
  141. }
  142. // byteBufferWAL is a WAL which writes all msgs to a byte buffer. Writing stops
  143. // when the heightToStop is reached. Client will be notified via
  144. // signalWhenStopsTo channel.
  145. type byteBufferWAL struct {
  146. enc *WALEncoder
  147. stopped bool
  148. heightToStop int64
  149. signalWhenStopsTo chan<- struct{}
  150. logger log.Logger
  151. }
  152. // needed for determinism
  153. var fixedTime, _ = time.Parse(time.RFC3339, "2017-01-02T15:04:05Z")
  154. func newByteBufferWAL(logger log.Logger, enc *WALEncoder, nBlocks int64, signalStop chan<- struct{}) *byteBufferWAL {
  155. return &byteBufferWAL{
  156. enc: enc,
  157. heightToStop: nBlocks,
  158. signalWhenStopsTo: signalStop,
  159. logger: logger,
  160. }
  161. }
  162. // Save writes message to the internal buffer except when heightToStop is
  163. // reached, in which case it will signal the caller via signalWhenStopsTo and
  164. // skip writing.
  165. func (w *byteBufferWAL) Write(m tmcon.WALMessage) error {
  166. if w.stopped {
  167. w.logger.Debug("WAL already stopped. Not writing message", "msg", m)
  168. return nil
  169. }
  170. if endMsg, ok := m.(tmcon.EndHeightMessage); ok {
  171. w.logger.Debug("WAL write end height message", "height", endMsg.Height, "stopHeight", w.heightToStop)
  172. if endMsg.Height == w.heightToStop {
  173. w.logger.Debug("Stopping WAL at height", "height", endMsg.Height)
  174. w.signalWhenStopsTo <- struct{}{}
  175. w.stopped = true
  176. return nil
  177. }
  178. }
  179. w.logger.Debug("WAL Write Message", "msg", m)
  180. err := w.enc.Encode(&tmcon.TimedWALMessage{Time: fixedTime, Msg: m})
  181. if err != nil {
  182. panic(fmt.Sprintf("failed to encode the msg %v", m))
  183. }
  184. return nil
  185. }
  186. func (w *byteBufferWAL) WriteSync(m tmcon.WALMessage) error {
  187. return w.Write(m)
  188. }
  189. func (w *byteBufferWAL) FlushAndSync() error { return nil }
  190. func (w *byteBufferWAL) SearchForEndHeight(
  191. height int64,
  192. options *tmcon.WALSearchOptions) (rd io.ReadCloser, found bool, err error) {
  193. return nil, false, nil
  194. }
  195. func (w *byteBufferWAL) Start() error { return nil }
  196. func (w *byteBufferWAL) Stop() error { return nil }
  197. func (w *byteBufferWAL) Wait() {}