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.

521 lines
15 KiB

blockchain: add v2 reactor (#4361) The work includes the reactor which ties together all the seperate routines involved in the design of the blockchain v2 refactor. This PR replaces #4067 which got far too large and messy after a failed attempt to rebase. ## Commits: * Blockchainv 2 reactor: + I cleaner copy of the work done in #4067 which fell too far behind and was a nightmare to rebase. + The work includes the reactor which ties together all the seperate routines involved in the design of the blockchain v2 refactor. * fixes after merge * reorder iIO interface methodset * change iO -> IO * panic before send nil block * rename switchToConsensus -> trySwitchToConsensus * rename tdState -> tmState * Update blockchain/v2/reactor.go Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * remove peer when it sends a block unsolicited * check for not ready in markReceived * fix error * fix the pcFinished event * typo fix * add documentation for processor fields * simplify time.Since * try and make the linter happy * some doc updates * fix channel diagram * Update adr-043-blockchain-riri-org.md * panic on nil switch * liting fixes * account for nil block in bBlockResponseMessage * panic on duplicate block enqueued by processor * linting * goimport reactor_test.go Co-authored-by: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> Co-authored-by: Anca Zamfir <ancazamfir@users.noreply.github.com> Co-authored-by: Marko <marbar3778@yahoo.com> Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
5 years ago
blockchain: add v2 reactor (#4361) The work includes the reactor which ties together all the seperate routines involved in the design of the blockchain v2 refactor. This PR replaces #4067 which got far too large and messy after a failed attempt to rebase. ## Commits: * Blockchainv 2 reactor: + I cleaner copy of the work done in #4067 which fell too far behind and was a nightmare to rebase. + The work includes the reactor which ties together all the seperate routines involved in the design of the blockchain v2 refactor. * fixes after merge * reorder iIO interface methodset * change iO -> IO * panic before send nil block * rename switchToConsensus -> trySwitchToConsensus * rename tdState -> tmState * Update blockchain/v2/reactor.go Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * remove peer when it sends a block unsolicited * check for not ready in markReceived * fix error * fix the pcFinished event * typo fix * add documentation for processor fields * simplify time.Since * try and make the linter happy * some doc updates * fix channel diagram * Update adr-043-blockchain-riri-org.md * panic on nil switch * liting fixes * account for nil block in bBlockResponseMessage * panic on duplicate block enqueued by processor * linting * goimport reactor_test.go Co-authored-by: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> Co-authored-by: Anca Zamfir <ancazamfir@users.noreply.github.com> Co-authored-by: Marko <marbar3778@yahoo.com> Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
5 years ago
blockchain: add v2 reactor (#4361) The work includes the reactor which ties together all the seperate routines involved in the design of the blockchain v2 refactor. This PR replaces #4067 which got far too large and messy after a failed attempt to rebase. ## Commits: * Blockchainv 2 reactor: + I cleaner copy of the work done in #4067 which fell too far behind and was a nightmare to rebase. + The work includes the reactor which ties together all the seperate routines involved in the design of the blockchain v2 refactor. * fixes after merge * reorder iIO interface methodset * change iO -> IO * panic before send nil block * rename switchToConsensus -> trySwitchToConsensus * rename tdState -> tmState * Update blockchain/v2/reactor.go Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * remove peer when it sends a block unsolicited * check for not ready in markReceived * fix error * fix the pcFinished event * typo fix * add documentation for processor fields * simplify time.Since * try and make the linter happy * some doc updates * fix channel diagram * Update adr-043-blockchain-riri-org.md * panic on nil switch * liting fixes * account for nil block in bBlockResponseMessage * panic on duplicate block enqueued by processor * linting * goimport reactor_test.go Co-authored-by: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> Co-authored-by: Anca Zamfir <ancazamfir@users.noreply.github.com> Co-authored-by: Marko <marbar3778@yahoo.com> Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
5 years ago
blockchain: add v2 reactor (#4361) The work includes the reactor which ties together all the seperate routines involved in the design of the blockchain v2 refactor. This PR replaces #4067 which got far too large and messy after a failed attempt to rebase. ## Commits: * Blockchainv 2 reactor: + I cleaner copy of the work done in #4067 which fell too far behind and was a nightmare to rebase. + The work includes the reactor which ties together all the seperate routines involved in the design of the blockchain v2 refactor. * fixes after merge * reorder iIO interface methodset * change iO -> IO * panic before send nil block * rename switchToConsensus -> trySwitchToConsensus * rename tdState -> tmState * Update blockchain/v2/reactor.go Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * remove peer when it sends a block unsolicited * check for not ready in markReceived * fix error * fix the pcFinished event * typo fix * add documentation for processor fields * simplify time.Since * try and make the linter happy * some doc updates * fix channel diagram * Update adr-043-blockchain-riri-org.md * panic on nil switch * liting fixes * account for nil block in bBlockResponseMessage * panic on duplicate block enqueued by processor * linting * goimport reactor_test.go Co-authored-by: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> Co-authored-by: Anca Zamfir <ancazamfir@users.noreply.github.com> Co-authored-by: Marko <marbar3778@yahoo.com> Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
5 years ago
5 years ago
blockchain: add v2 reactor (#4361) The work includes the reactor which ties together all the seperate routines involved in the design of the blockchain v2 refactor. This PR replaces #4067 which got far too large and messy after a failed attempt to rebase. ## Commits: * Blockchainv 2 reactor: + I cleaner copy of the work done in #4067 which fell too far behind and was a nightmare to rebase. + The work includes the reactor which ties together all the seperate routines involved in the design of the blockchain v2 refactor. * fixes after merge * reorder iIO interface methodset * change iO -> IO * panic before send nil block * rename switchToConsensus -> trySwitchToConsensus * rename tdState -> tmState * Update blockchain/v2/reactor.go Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * remove peer when it sends a block unsolicited * check for not ready in markReceived * fix error * fix the pcFinished event * typo fix * add documentation for processor fields * simplify time.Since * try and make the linter happy * some doc updates * fix channel diagram * Update adr-043-blockchain-riri-org.md * panic on nil switch * liting fixes * account for nil block in bBlockResponseMessage * panic on duplicate block enqueued by processor * linting * goimport reactor_test.go Co-authored-by: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> Co-authored-by: Anca Zamfir <ancazamfir@users.noreply.github.com> Co-authored-by: Marko <marbar3778@yahoo.com> Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
5 years ago
5 years ago
blockchain: add v2 reactor (#4361) The work includes the reactor which ties together all the seperate routines involved in the design of the blockchain v2 refactor. This PR replaces #4067 which got far too large and messy after a failed attempt to rebase. ## Commits: * Blockchainv 2 reactor: + I cleaner copy of the work done in #4067 which fell too far behind and was a nightmare to rebase. + The work includes the reactor which ties together all the seperate routines involved in the design of the blockchain v2 refactor. * fixes after merge * reorder iIO interface methodset * change iO -> IO * panic before send nil block * rename switchToConsensus -> trySwitchToConsensus * rename tdState -> tmState * Update blockchain/v2/reactor.go Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * remove peer when it sends a block unsolicited * check for not ready in markReceived * fix error * fix the pcFinished event * typo fix * add documentation for processor fields * simplify time.Since * try and make the linter happy * some doc updates * fix channel diagram * Update adr-043-blockchain-riri-org.md * panic on nil switch * liting fixes * account for nil block in bBlockResponseMessage * panic on duplicate block enqueued by processor * linting * goimport reactor_test.go Co-authored-by: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> Co-authored-by: Anca Zamfir <ancazamfir@users.noreply.github.com> Co-authored-by: Marko <marbar3778@yahoo.com> Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
5 years ago
blockchain: add v2 reactor (#4361) The work includes the reactor which ties together all the seperate routines involved in the design of the blockchain v2 refactor. This PR replaces #4067 which got far too large and messy after a failed attempt to rebase. ## Commits: * Blockchainv 2 reactor: + I cleaner copy of the work done in #4067 which fell too far behind and was a nightmare to rebase. + The work includes the reactor which ties together all the seperate routines involved in the design of the blockchain v2 refactor. * fixes after merge * reorder iIO interface methodset * change iO -> IO * panic before send nil block * rename switchToConsensus -> trySwitchToConsensus * rename tdState -> tmState * Update blockchain/v2/reactor.go Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * remove peer when it sends a block unsolicited * check for not ready in markReceived * fix error * fix the pcFinished event * typo fix * add documentation for processor fields * simplify time.Since * try and make the linter happy * some doc updates * fix channel diagram * Update adr-043-blockchain-riri-org.md * panic on nil switch * liting fixes * account for nil block in bBlockResponseMessage * panic on duplicate block enqueued by processor * linting * goimport reactor_test.go Co-authored-by: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> Co-authored-by: Anca Zamfir <ancazamfir@users.noreply.github.com> Co-authored-by: Marko <marbar3778@yahoo.com> Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
5 years ago
blockchain: add v2 reactor (#4361) The work includes the reactor which ties together all the seperate routines involved in the design of the blockchain v2 refactor. This PR replaces #4067 which got far too large and messy after a failed attempt to rebase. ## Commits: * Blockchainv 2 reactor: + I cleaner copy of the work done in #4067 which fell too far behind and was a nightmare to rebase. + The work includes the reactor which ties together all the seperate routines involved in the design of the blockchain v2 refactor. * fixes after merge * reorder iIO interface methodset * change iO -> IO * panic before send nil block * rename switchToConsensus -> trySwitchToConsensus * rename tdState -> tmState * Update blockchain/v2/reactor.go Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * remove peer when it sends a block unsolicited * check for not ready in markReceived * fix error * fix the pcFinished event * typo fix * add documentation for processor fields * simplify time.Since * try and make the linter happy * some doc updates * fix channel diagram * Update adr-043-blockchain-riri-org.md * panic on nil switch * liting fixes * account for nil block in bBlockResponseMessage * panic on duplicate block enqueued by processor * linting * goimport reactor_test.go Co-authored-by: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> Co-authored-by: Anca Zamfir <ancazamfir@users.noreply.github.com> Co-authored-by: Marko <marbar3778@yahoo.com> Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
5 years ago
blockchain: add v2 reactor (#4361) The work includes the reactor which ties together all the seperate routines involved in the design of the blockchain v2 refactor. This PR replaces #4067 which got far too large and messy after a failed attempt to rebase. ## Commits: * Blockchainv 2 reactor: + I cleaner copy of the work done in #4067 which fell too far behind and was a nightmare to rebase. + The work includes the reactor which ties together all the seperate routines involved in the design of the blockchain v2 refactor. * fixes after merge * reorder iIO interface methodset * change iO -> IO * panic before send nil block * rename switchToConsensus -> trySwitchToConsensus * rename tdState -> tmState * Update blockchain/v2/reactor.go Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * remove peer when it sends a block unsolicited * check for not ready in markReceived * fix error * fix the pcFinished event * typo fix * add documentation for processor fields * simplify time.Since * try and make the linter happy * some doc updates * fix channel diagram * Update adr-043-blockchain-riri-org.md * panic on nil switch * liting fixes * account for nil block in bBlockResponseMessage * panic on duplicate block enqueued by processor * linting * goimport reactor_test.go Co-authored-by: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> Co-authored-by: Anca Zamfir <ancazamfir@users.noreply.github.com> Co-authored-by: Marko <marbar3778@yahoo.com> Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
5 years ago
blockchain: add v2 reactor (#4361) The work includes the reactor which ties together all the seperate routines involved in the design of the blockchain v2 refactor. This PR replaces #4067 which got far too large and messy after a failed attempt to rebase. ## Commits: * Blockchainv 2 reactor: + I cleaner copy of the work done in #4067 which fell too far behind and was a nightmare to rebase. + The work includes the reactor which ties together all the seperate routines involved in the design of the blockchain v2 refactor. * fixes after merge * reorder iIO interface methodset * change iO -> IO * panic before send nil block * rename switchToConsensus -> trySwitchToConsensus * rename tdState -> tmState * Update blockchain/v2/reactor.go Co-Authored-By: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> * remove peer when it sends a block unsolicited * check for not ready in markReceived * fix error * fix the pcFinished event * typo fix * add documentation for processor fields * simplify time.Since * try and make the linter happy * some doc updates * fix channel diagram * Update adr-043-blockchain-riri-org.md * panic on nil switch * liting fixes * account for nil block in bBlockResponseMessage * panic on duplicate block enqueued by processor * linting * goimport reactor_test.go Co-authored-by: Bot from GolangCI <42910462+golangcibot@users.noreply.github.com> Co-authored-by: Anca Zamfir <ancazamfir@users.noreply.github.com> Co-authored-by: Marko <marbar3778@yahoo.com> Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
5 years ago
  1. package v2
  2. import (
  3. "net"
  4. "os"
  5. "sort"
  6. "sync"
  7. "testing"
  8. "time"
  9. "github.com/pkg/errors"
  10. "github.com/stretchr/testify/assert"
  11. abci "github.com/tendermint/tendermint/abci/types"
  12. "github.com/tendermint/tendermint/behaviour"
  13. cfg "github.com/tendermint/tendermint/config"
  14. "github.com/tendermint/tendermint/libs/log"
  15. "github.com/tendermint/tendermint/libs/service"
  16. "github.com/tendermint/tendermint/mock"
  17. "github.com/tendermint/tendermint/p2p"
  18. "github.com/tendermint/tendermint/p2p/conn"
  19. "github.com/tendermint/tendermint/proxy"
  20. sm "github.com/tendermint/tendermint/state"
  21. "github.com/tendermint/tendermint/store"
  22. "github.com/tendermint/tendermint/types"
  23. tmtime "github.com/tendermint/tendermint/types/time"
  24. dbm "github.com/tendermint/tm-db"
  25. )
  26. type mockPeer struct {
  27. service.Service
  28. id p2p.ID
  29. }
  30. func (mp mockPeer) FlushStop() {}
  31. func (mp mockPeer) ID() p2p.ID { return mp.id }
  32. func (mp mockPeer) RemoteIP() net.IP { return net.IP{} }
  33. func (mp mockPeer) RemoteAddr() net.Addr { return &net.TCPAddr{IP: mp.RemoteIP(), Port: 8800} }
  34. func (mp mockPeer) IsOutbound() bool { return true }
  35. func (mp mockPeer) IsPersistent() bool { return true }
  36. func (mp mockPeer) CloseConn() error { return nil }
  37. func (mp mockPeer) NodeInfo() p2p.NodeInfo {
  38. return p2p.DefaultNodeInfo{
  39. DefaultNodeID: "",
  40. ListenAddr: "",
  41. }
  42. }
  43. func (mp mockPeer) Status() conn.ConnectionStatus { return conn.ConnectionStatus{} }
  44. func (mp mockPeer) SocketAddr() *p2p.NetAddress { return &p2p.NetAddress{} }
  45. func (mp mockPeer) Send(byte, []byte) bool { return true }
  46. func (mp mockPeer) TrySend(byte, []byte) bool { return true }
  47. func (mp mockPeer) Set(string, interface{}) {}
  48. func (mp mockPeer) Get(string) interface{} { return struct{}{} }
  49. //nolint:unused
  50. type mockBlockStore struct {
  51. blocks map[int64]*types.Block
  52. }
  53. func (ml *mockBlockStore) Height() int64 {
  54. return int64(len(ml.blocks))
  55. }
  56. func (ml *mockBlockStore) LoadBlock(height int64) *types.Block {
  57. return ml.blocks[height]
  58. }
  59. func (ml *mockBlockStore) SaveBlock(block *types.Block, part *types.PartSet, commit *types.Commit) {
  60. ml.blocks[block.Height] = block
  61. }
  62. type mockBlockApplier struct {
  63. }
  64. // XXX: Add whitelist/blacklist?
  65. func (mba *mockBlockApplier) ApplyBlock(state sm.State, blockID types.BlockID, block *types.Block) (sm.State, error) {
  66. state.LastBlockHeight++
  67. return state, nil
  68. }
  69. type mockSwitchIo struct {
  70. mtx sync.Mutex
  71. switchedToConsensus bool
  72. numStatusResponse int
  73. numBlockResponse int
  74. numNoBlockResponse int
  75. }
  76. func (sio *mockSwitchIo) sendBlockRequest(peerID p2p.ID, height int64) error {
  77. return nil
  78. }
  79. func (sio *mockSwitchIo) sendStatusResponse(height int64, peerID p2p.ID) error {
  80. sio.mtx.Lock()
  81. defer sio.mtx.Unlock()
  82. sio.numStatusResponse++
  83. return nil
  84. }
  85. func (sio *mockSwitchIo) sendBlockToPeer(block *types.Block, peerID p2p.ID) error {
  86. sio.mtx.Lock()
  87. defer sio.mtx.Unlock()
  88. sio.numBlockResponse++
  89. return nil
  90. }
  91. func (sio *mockSwitchIo) sendBlockNotFound(height int64, peerID p2p.ID) error {
  92. sio.mtx.Lock()
  93. defer sio.mtx.Unlock()
  94. sio.numNoBlockResponse++
  95. return nil
  96. }
  97. func (sio *mockSwitchIo) trySwitchToConsensus(state sm.State, blocksSynced int) {
  98. sio.mtx.Lock()
  99. defer sio.mtx.Unlock()
  100. sio.switchedToConsensus = true
  101. }
  102. func (sio *mockSwitchIo) hasSwitchedToConsensus() bool {
  103. sio.mtx.Lock()
  104. defer sio.mtx.Unlock()
  105. return sio.switchedToConsensus
  106. }
  107. func (sio *mockSwitchIo) broadcastStatusRequest(height int64) {
  108. }
  109. type testReactorParams struct {
  110. logger log.Logger
  111. genDoc *types.GenesisDoc
  112. privVals []types.PrivValidator
  113. startHeight int64
  114. bufferSize int
  115. mockA bool
  116. }
  117. func newTestReactor(p testReactorParams) *BlockchainReactor {
  118. store, state, _ := newReactorStore(p.genDoc, p.privVals, p.startHeight)
  119. reporter := behaviour.NewMockReporter()
  120. var appl blockApplier
  121. if p.mockA {
  122. appl = &mockBlockApplier{}
  123. } else {
  124. app := &testApp{}
  125. cc := proxy.NewLocalClientCreator(app)
  126. proxyApp := proxy.NewAppConns(cc)
  127. err := proxyApp.Start()
  128. if err != nil {
  129. panic(errors.Wrap(err, "error start app"))
  130. }
  131. db := dbm.NewMemDB()
  132. appl = sm.NewBlockExecutor(db, p.logger, proxyApp.Consensus(), mock.Mempool{}, sm.MockEvidencePool{})
  133. sm.SaveState(db, state)
  134. }
  135. r := newReactor(state, store, reporter, appl, p.bufferSize)
  136. logger := log.TestingLogger()
  137. r.SetLogger(logger.With("module", "blockchain"))
  138. return r
  139. }
  140. // This test is left here and not deleted to retain the termination cases for
  141. // future improvement in [#4482](https://github.com/tendermint/tendermint/issues/4482).
  142. // func TestReactorTerminationScenarios(t *testing.T) {
  143. // config := cfg.ResetTestRoot("blockchain_reactor_v2_test")
  144. // defer os.RemoveAll(config.RootDir)
  145. // genDoc, privVals := randGenesisDoc(config.ChainID(), 1, false, 30)
  146. // refStore, _, _ := newReactorStore(genDoc, privVals, 20)
  147. // params := testReactorParams{
  148. // logger: log.TestingLogger(),
  149. // genDoc: genDoc,
  150. // privVals: privVals,
  151. // startHeight: 10,
  152. // bufferSize: 100,
  153. // mockA: true,
  154. // }
  155. // type testEvent struct {
  156. // evType string
  157. // peer string
  158. // height int64
  159. // }
  160. // tests := []struct {
  161. // name string
  162. // params testReactorParams
  163. // msgs []testEvent
  164. // }{
  165. // {
  166. // name: "simple termination on max peer height - one peer",
  167. // params: params,
  168. // msgs: []testEvent{
  169. // {evType: "AddPeer", peer: "P1"},
  170. // {evType: "ReceiveS", peer: "P1", height: 13},
  171. // {evType: "BlockReq"},
  172. // {evType: "ReceiveB", peer: "P1", height: 11},
  173. // {evType: "BlockReq"},
  174. // {evType: "BlockReq"},
  175. // {evType: "ReceiveB", peer: "P1", height: 12},
  176. // {evType: "Process"},
  177. // {evType: "ReceiveB", peer: "P1", height: 13},
  178. // {evType: "Process"},
  179. // },
  180. // },
  181. // {
  182. // name: "simple termination on max peer height - two peers",
  183. // params: params,
  184. // msgs: []testEvent{
  185. // {evType: "AddPeer", peer: "P1"},
  186. // {evType: "AddPeer", peer: "P2"},
  187. // {evType: "ReceiveS", peer: "P1", height: 13},
  188. // {evType: "ReceiveS", peer: "P2", height: 15},
  189. // {evType: "BlockReq"},
  190. // {evType: "BlockReq"},
  191. // {evType: "ReceiveB", peer: "P1", height: 11},
  192. // {evType: "ReceiveB", peer: "P2", height: 12},
  193. // {evType: "Process"},
  194. // {evType: "BlockReq"},
  195. // {evType: "BlockReq"},
  196. // {evType: "ReceiveB", peer: "P1", height: 13},
  197. // {evType: "Process"},
  198. // {evType: "ReceiveB", peer: "P2", height: 14},
  199. // {evType: "Process"},
  200. // {evType: "BlockReq"},
  201. // {evType: "ReceiveB", peer: "P2", height: 15},
  202. // {evType: "Process"},
  203. // },
  204. // },
  205. // {
  206. // name: "termination on max peer height - two peers, noBlock error",
  207. // params: params,
  208. // msgs: []testEvent{
  209. // {evType: "AddPeer", peer: "P1"},
  210. // {evType: "AddPeer", peer: "P2"},
  211. // {evType: "ReceiveS", peer: "P1", height: 13},
  212. // {evType: "ReceiveS", peer: "P2", height: 15},
  213. // {evType: "BlockReq"},
  214. // {evType: "BlockReq"},
  215. // {evType: "ReceiveNB", peer: "P1", height: 11},
  216. // {evType: "BlockReq"},
  217. // {evType: "ReceiveB", peer: "P2", height: 12},
  218. // {evType: "ReceiveB", peer: "P2", height: 11},
  219. // {evType: "Process"},
  220. // {evType: "BlockReq"},
  221. // {evType: "BlockReq"},
  222. // {evType: "ReceiveB", peer: "P2", height: 13},
  223. // {evType: "Process"},
  224. // {evType: "ReceiveB", peer: "P2", height: 14},
  225. // {evType: "Process"},
  226. // {evType: "BlockReq"},
  227. // {evType: "ReceiveB", peer: "P2", height: 15},
  228. // {evType: "Process"},
  229. // },
  230. // },
  231. // {
  232. // name: "termination on max peer height - two peers, remove one peer",
  233. // params: params,
  234. // msgs: []testEvent{
  235. // {evType: "AddPeer", peer: "P1"},
  236. // {evType: "AddPeer", peer: "P2"},
  237. // {evType: "ReceiveS", peer: "P1", height: 13},
  238. // {evType: "ReceiveS", peer: "P2", height: 15},
  239. // {evType: "BlockReq"},
  240. // {evType: "BlockReq"},
  241. // {evType: "RemovePeer", peer: "P1"},
  242. // {evType: "BlockReq"},
  243. // {evType: "ReceiveB", peer: "P2", height: 12},
  244. // {evType: "ReceiveB", peer: "P2", height: 11},
  245. // {evType: "Process"},
  246. // {evType: "BlockReq"},
  247. // {evType: "BlockReq"},
  248. // {evType: "ReceiveB", peer: "P2", height: 13},
  249. // {evType: "Process"},
  250. // {evType: "ReceiveB", peer: "P2", height: 14},
  251. // {evType: "Process"},
  252. // {evType: "BlockReq"},
  253. // {evType: "ReceiveB", peer: "P2", height: 15},
  254. // {evType: "Process"},
  255. // },
  256. // },
  257. // }
  258. // for _, tt := range tests {
  259. // tt := tt
  260. // t.Run(tt.name, func(t *testing.T) {
  261. // reactor := newTestReactor(params)
  262. // reactor.Start()
  263. // reactor.reporter = behaviour.NewMockReporter()
  264. // mockSwitch := &mockSwitchIo{switchedToConsensus: false}
  265. // reactor.io = mockSwitch
  266. // // time for go routines to start
  267. // time.Sleep(time.Millisecond)
  268. // for _, step := range tt.msgs {
  269. // switch step.evType {
  270. // case "AddPeer":
  271. // reactor.scheduler.send(bcAddNewPeer{peerID: p2p.ID(step.peer)})
  272. // case "RemovePeer":
  273. // reactor.scheduler.send(bcRemovePeer{peerID: p2p.ID(step.peer)})
  274. // case "ReceiveS":
  275. // reactor.scheduler.send(bcStatusResponse{
  276. // peerID: p2p.ID(step.peer),
  277. // height: step.height,
  278. // time: time.Now(),
  279. // })
  280. // case "ReceiveB":
  281. // reactor.scheduler.send(bcBlockResponse{
  282. // peerID: p2p.ID(step.peer),
  283. // block: refStore.LoadBlock(step.height),
  284. // size: 10,
  285. // time: time.Now(),
  286. // })
  287. // case "ReceiveNB":
  288. // reactor.scheduler.send(bcNoBlockResponse{
  289. // peerID: p2p.ID(step.peer),
  290. // height: step.height,
  291. // time: time.Now(),
  292. // })
  293. // case "BlockReq":
  294. // reactor.scheduler.send(rTrySchedule{time: time.Now()})
  295. // case "Process":
  296. // reactor.processor.send(rProcessBlock{})
  297. // }
  298. // // give time for messages to propagate between routines
  299. // time.Sleep(time.Millisecond)
  300. // }
  301. // // time for processor to finish and reactor to switch to consensus
  302. // time.Sleep(20 * time.Millisecond)
  303. // assert.True(t, mockSwitch.hasSwitchedToConsensus())
  304. // reactor.Stop()
  305. // })
  306. // }
  307. // }
  308. func TestReactorHelperMode(t *testing.T) {
  309. var (
  310. channelID = byte(0x40)
  311. )
  312. config := cfg.ResetTestRoot("blockchain_reactor_v2_test")
  313. defer os.RemoveAll(config.RootDir)
  314. genDoc, privVals := randGenesisDoc(config.ChainID(), 1, false, 30)
  315. params := testReactorParams{
  316. logger: log.TestingLogger(),
  317. genDoc: genDoc,
  318. privVals: privVals,
  319. startHeight: 20,
  320. bufferSize: 100,
  321. mockA: true,
  322. }
  323. type testEvent struct {
  324. peer string
  325. event interface{}
  326. }
  327. tests := []struct {
  328. name string
  329. params testReactorParams
  330. msgs []testEvent
  331. }{
  332. {
  333. name: "status request",
  334. params: params,
  335. msgs: []testEvent{
  336. {"P1", bcStatusRequestMessage{}},
  337. {"P1", bcBlockRequestMessage{Height: 13}},
  338. {"P1", bcBlockRequestMessage{Height: 20}},
  339. {"P1", bcBlockRequestMessage{Height: 22}},
  340. },
  341. },
  342. }
  343. for _, tt := range tests {
  344. tt := tt
  345. t.Run(tt.name, func(t *testing.T) {
  346. reactor := newTestReactor(params)
  347. reactor.Start()
  348. mockSwitch := &mockSwitchIo{switchedToConsensus: false}
  349. reactor.io = mockSwitch
  350. for i := 0; i < len(tt.msgs); i++ {
  351. step := tt.msgs[i]
  352. switch ev := step.event.(type) {
  353. case bcStatusRequestMessage:
  354. old := mockSwitch.numStatusResponse
  355. reactor.Receive(channelID, mockPeer{id: p2p.ID(step.peer)}, cdc.MustMarshalBinaryBare(ev))
  356. assert.Equal(t, old+1, mockSwitch.numStatusResponse)
  357. case bcBlockRequestMessage:
  358. if ev.Height > params.startHeight {
  359. old := mockSwitch.numNoBlockResponse
  360. reactor.Receive(channelID, mockPeer{id: p2p.ID(step.peer)}, cdc.MustMarshalBinaryBare(ev))
  361. assert.Equal(t, old+1, mockSwitch.numNoBlockResponse)
  362. } else {
  363. old := mockSwitch.numBlockResponse
  364. reactor.Receive(channelID, mockPeer{id: p2p.ID(step.peer)}, cdc.MustMarshalBinaryBare(ev))
  365. assert.Equal(t, old+1, mockSwitch.numBlockResponse)
  366. }
  367. }
  368. }
  369. reactor.Stop()
  370. })
  371. }
  372. }
  373. //----------------------------------------------
  374. // utility funcs
  375. func makeTxs(height int64) (txs []types.Tx) {
  376. for i := 0; i < 10; i++ {
  377. txs = append(txs, types.Tx([]byte{byte(height), byte(i)}))
  378. }
  379. return txs
  380. }
  381. func makeBlock(height int64, state sm.State, lastCommit *types.Commit) *types.Block {
  382. block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil, state.Validators.GetProposer().Address)
  383. return block
  384. }
  385. type testApp struct {
  386. abci.BaseApplication
  387. }
  388. func randGenesisDoc(chainID string, numValidators int, randPower bool, minPower int64) (
  389. *types.GenesisDoc, []types.PrivValidator) {
  390. validators := make([]types.GenesisValidator, numValidators)
  391. privValidators := make([]types.PrivValidator, numValidators)
  392. for i := 0; i < numValidators; i++ {
  393. val, privVal := types.RandValidator(randPower, minPower)
  394. validators[i] = types.GenesisValidator{
  395. PubKey: val.PubKey,
  396. Power: val.VotingPower,
  397. }
  398. privValidators[i] = privVal
  399. }
  400. sort.Sort(types.PrivValidatorsByAddress(privValidators))
  401. return &types.GenesisDoc{
  402. GenesisTime: tmtime.Now(),
  403. ChainID: chainID,
  404. Validators: validators,
  405. }, privValidators
  406. }
  407. // Why are we importing the entire blockExecutor dependency graph here
  408. // when we have the facilities to
  409. func newReactorStore(
  410. genDoc *types.GenesisDoc,
  411. privVals []types.PrivValidator,
  412. maxBlockHeight int64) (*store.BlockStore, sm.State, *sm.BlockExecutor) {
  413. if len(privVals) != 1 {
  414. panic("only support one validator")
  415. }
  416. app := &testApp{}
  417. cc := proxy.NewLocalClientCreator(app)
  418. proxyApp := proxy.NewAppConns(cc)
  419. err := proxyApp.Start()
  420. if err != nil {
  421. panic(errors.Wrap(err, "error start app"))
  422. }
  423. stateDB := dbm.NewMemDB()
  424. blockStore := store.NewBlockStore(dbm.NewMemDB())
  425. state, err := sm.LoadStateFromDBOrGenesisDoc(stateDB, genDoc)
  426. if err != nil {
  427. panic(errors.Wrap(err, "error constructing state from genesis file"))
  428. }
  429. db := dbm.NewMemDB()
  430. blockExec := sm.NewBlockExecutor(db, log.TestingLogger(), proxyApp.Consensus(),
  431. mock.Mempool{}, sm.MockEvidencePool{})
  432. sm.SaveState(db, state)
  433. // add blocks in
  434. for blockHeight := int64(1); blockHeight <= maxBlockHeight; blockHeight++ {
  435. lastCommit := types.NewCommit(blockHeight-1, 0, types.BlockID{}, nil)
  436. if blockHeight > 1 {
  437. lastBlockMeta := blockStore.LoadBlockMeta(blockHeight - 1)
  438. lastBlock := blockStore.LoadBlock(blockHeight - 1)
  439. vote, err := types.MakeVote(
  440. lastBlock.Header.Height,
  441. lastBlockMeta.BlockID,
  442. state.Validators,
  443. privVals[0],
  444. lastBlock.Header.ChainID,
  445. time.Now(),
  446. )
  447. if err != nil {
  448. panic(err)
  449. }
  450. lastCommit = types.NewCommit(vote.Height, vote.Round,
  451. lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()})
  452. }
  453. thisBlock := makeBlock(blockHeight, state, lastCommit)
  454. thisParts := thisBlock.MakePartSet(types.BlockPartSizeBytes)
  455. blockID := types.BlockID{Hash: thisBlock.Hash(), PartsHeader: thisParts.Header()}
  456. state, err = blockExec.ApplyBlock(state, blockID, thisBlock)
  457. if err != nil {
  458. panic(errors.Wrap(err, "error apply block"))
  459. }
  460. blockStore.SaveBlock(thisBlock, thisParts, lastCommit)
  461. }
  462. return blockStore, state, blockExec
  463. }