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.

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