github.com/MagHErmit/tendermint@v0.282.1/mempool/v0/reactor_test.go (about) 1 package v0 2 3 import ( 4 "encoding/hex" 5 "errors" 6 "net" 7 "sync" 8 "testing" 9 "time" 10 11 "github.com/fortytw2/leaktest" 12 "github.com/go-kit/log/term" 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 16 "github.com/MagHErmit/tendermint/abci/example/kvstore" 17 abci "github.com/MagHErmit/tendermint/abci/types" 18 cfg "github.com/MagHErmit/tendermint/config" 19 "github.com/MagHErmit/tendermint/libs/log" 20 tmrand "github.com/MagHErmit/tendermint/libs/rand" 21 "github.com/MagHErmit/tendermint/mempool" 22 "github.com/MagHErmit/tendermint/p2p" 23 "github.com/MagHErmit/tendermint/p2p/mock" 24 memproto "github.com/MagHErmit/tendermint/proto/tendermint/mempool" 25 "github.com/MagHErmit/tendermint/proxy" 26 "github.com/MagHErmit/tendermint/types" 27 ) 28 29 const ( 30 numTxs = 1000 31 timeout = 120 * time.Second // ridiculously high because CircleCI is slow 32 ) 33 34 type peerState struct { 35 height int64 36 } 37 38 func (ps peerState) GetHeight() int64 { 39 return ps.height 40 } 41 42 // Send a bunch of txs to the first reactor's mempool and wait for them all to 43 // be received in the others. 44 func TestReactorBroadcastTxsMessage(t *testing.T) { 45 config := cfg.TestConfig() 46 // if there were more than two reactors, the order of transactions could not be 47 // asserted in waitForTxsOnReactors (due to transactions gossiping). If we 48 // replace Connect2Switches (full mesh) with a func, which connects first 49 // reactor to others and nothing else, this test should also pass with >2 reactors. 50 const N = 2 51 reactors := makeAndConnectReactors(config, N) 52 defer func() { 53 for _, r := range reactors { 54 if err := r.Stop(); err != nil { 55 assert.NoError(t, err) 56 } 57 } 58 }() 59 for _, r := range reactors { 60 for _, peer := range r.Switch.Peers().List() { 61 peer.Set(types.PeerStateKey, peerState{1}) 62 } 63 } 64 65 txs := checkTxs(t, reactors[0].mempool, numTxs, mempool.UnknownPeerID) 66 waitForTxsOnReactors(t, txs, reactors) 67 } 68 69 // regression test for https://github.com/MagHErmit/tendermint/issues/5408 70 func TestReactorConcurrency(t *testing.T) { 71 config := cfg.TestConfig() 72 const N = 2 73 reactors := makeAndConnectReactors(config, N) 74 defer func() { 75 for _, r := range reactors { 76 if err := r.Stop(); err != nil { 77 assert.NoError(t, err) 78 } 79 } 80 }() 81 for _, r := range reactors { 82 for _, peer := range r.Switch.Peers().List() { 83 peer.Set(types.PeerStateKey, peerState{1}) 84 } 85 } 86 var wg sync.WaitGroup 87 88 const numTxs = 5 89 90 for i := 0; i < 1000; i++ { 91 wg.Add(2) 92 93 // 1. submit a bunch of txs 94 // 2. update the whole mempool 95 txs := checkTxs(t, reactors[0].mempool, numTxs, mempool.UnknownPeerID) 96 go func() { 97 defer wg.Done() 98 99 reactors[0].mempool.Lock() 100 defer reactors[0].mempool.Unlock() 101 102 deliverTxResponses := make([]*abci.ResponseDeliverTx, len(txs)) 103 for i := range txs { 104 deliverTxResponses[i] = &abci.ResponseDeliverTx{Code: 0} 105 } 106 err := reactors[0].mempool.Update(1, txs, deliverTxResponses, nil, nil) 107 assert.NoError(t, err) 108 }() 109 110 // 1. submit a bunch of txs 111 // 2. update none 112 _ = checkTxs(t, reactors[1].mempool, numTxs, mempool.UnknownPeerID) 113 go func() { 114 defer wg.Done() 115 116 reactors[1].mempool.Lock() 117 defer reactors[1].mempool.Unlock() 118 err := reactors[1].mempool.Update(1, []types.Tx{}, make([]*abci.ResponseDeliverTx, 0), nil, nil) 119 assert.NoError(t, err) 120 }() 121 122 // 1. flush the mempool 123 reactors[1].mempool.Flush() 124 } 125 126 wg.Wait() 127 } 128 129 // Send a bunch of txs to the first reactor's mempool, claiming it came from peer 130 // ensure peer gets no txs. 131 func TestReactorNoBroadcastToSender(t *testing.T) { 132 config := cfg.TestConfig() 133 const N = 2 134 reactors := makeAndConnectReactors(config, N) 135 defer func() { 136 for _, r := range reactors { 137 if err := r.Stop(); err != nil { 138 assert.NoError(t, err) 139 } 140 } 141 }() 142 for _, r := range reactors { 143 for _, peer := range r.Switch.Peers().List() { 144 peer.Set(types.PeerStateKey, peerState{1}) 145 } 146 } 147 148 const peerID = 1 149 checkTxs(t, reactors[0].mempool, numTxs, peerID) 150 ensureNoTxs(t, reactors[peerID], 100*time.Millisecond) 151 } 152 153 func TestReactor_MaxTxBytes(t *testing.T) { 154 config := cfg.TestConfig() 155 156 const N = 2 157 reactors := makeAndConnectReactors(config, N) 158 defer func() { 159 for _, r := range reactors { 160 if err := r.Stop(); err != nil { 161 assert.NoError(t, err) 162 } 163 } 164 }() 165 for _, r := range reactors { 166 for _, peer := range r.Switch.Peers().List() { 167 peer.Set(types.PeerStateKey, peerState{1}) 168 } 169 } 170 171 // Broadcast a tx, which has the max size 172 // => ensure it's received by the second reactor. 173 tx1 := tmrand.Bytes(config.Mempool.MaxTxBytes) 174 err := reactors[0].mempool.CheckTx(tx1, nil, mempool.TxInfo{SenderID: mempool.UnknownPeerID}) 175 require.NoError(t, err) 176 waitForTxsOnReactors(t, []types.Tx{tx1}, reactors) 177 178 reactors[0].mempool.Flush() 179 reactors[1].mempool.Flush() 180 181 // Broadcast a tx, which is beyond the max size 182 // => ensure it's not sent 183 tx2 := tmrand.Bytes(config.Mempool.MaxTxBytes + 1) 184 err = reactors[0].mempool.CheckTx(tx2, nil, mempool.TxInfo{SenderID: mempool.UnknownPeerID}) 185 require.Error(t, err) 186 } 187 188 func TestBroadcastTxForPeerStopsWhenPeerStops(t *testing.T) { 189 if testing.Short() { 190 t.Skip("skipping test in short mode.") 191 } 192 193 config := cfg.TestConfig() 194 const N = 2 195 reactors := makeAndConnectReactors(config, N) 196 defer func() { 197 for _, r := range reactors { 198 if err := r.Stop(); err != nil { 199 assert.NoError(t, err) 200 } 201 } 202 }() 203 204 // stop peer 205 sw := reactors[1].Switch 206 sw.StopPeerForError(sw.Peers().List()[0], errors.New("some reason")) 207 208 // check that we are not leaking any go-routines 209 // i.e. broadcastTxRoutine finishes when peer is stopped 210 leaktest.CheckTimeout(t, 10*time.Second)() 211 } 212 213 func TestBroadcastTxForPeerStopsWhenReactorStops(t *testing.T) { 214 if testing.Short() { 215 t.Skip("skipping test in short mode.") 216 } 217 218 config := cfg.TestConfig() 219 const N = 2 220 reactors := makeAndConnectReactors(config, N) 221 222 // stop reactors 223 for _, r := range reactors { 224 if err := r.Stop(); err != nil { 225 assert.NoError(t, err) 226 } 227 } 228 229 // check that we are not leaking any go-routines 230 // i.e. broadcastTxRoutine finishes when reactor is stopped 231 leaktest.CheckTimeout(t, 10*time.Second)() 232 } 233 234 func TestMempoolIDsBasic(t *testing.T) { 235 ids := newMempoolIDs() 236 237 peer := mock.NewPeer(net.IP{127, 0, 0, 1}) 238 239 ids.ReserveForPeer(peer) 240 assert.EqualValues(t, 1, ids.GetForPeer(peer)) 241 ids.Reclaim(peer) 242 243 ids.ReserveForPeer(peer) 244 assert.EqualValues(t, 2, ids.GetForPeer(peer)) 245 ids.Reclaim(peer) 246 } 247 248 func TestMempoolIDsPanicsIfNodeRequestsOvermaxActiveIDs(t *testing.T) { 249 if testing.Short() { 250 return 251 } 252 253 // 0 is already reserved for UnknownPeerID 254 ids := newMempoolIDs() 255 256 for i := 0; i < mempool.MaxActiveIDs-1; i++ { 257 peer := mock.NewPeer(net.IP{127, 0, 0, 1}) 258 ids.ReserveForPeer(peer) 259 } 260 261 assert.Panics(t, func() { 262 peer := mock.NewPeer(net.IP{127, 0, 0, 1}) 263 ids.ReserveForPeer(peer) 264 }) 265 } 266 267 func TestDontExhaustMaxActiveIDs(t *testing.T) { 268 config := cfg.TestConfig() 269 const N = 1 270 reactors := makeAndConnectReactors(config, N) 271 defer func() { 272 for _, r := range reactors { 273 if err := r.Stop(); err != nil { 274 assert.NoError(t, err) 275 } 276 } 277 }() 278 reactor := reactors[0] 279 280 for i := 0; i < mempool.MaxActiveIDs+1; i++ { 281 peer := mock.NewPeer(nil) 282 reactor.Receive(mempool.MempoolChannel, peer, []byte{0x1, 0x2, 0x3}) 283 reactor.AddPeer(peer) 284 } 285 } 286 287 // mempoolLogger is a TestingLogger which uses a different 288 // color for each validator ("validator" key must exist). 289 func mempoolLogger() log.Logger { 290 return log.TestingLoggerWithColorFn(func(keyvals ...interface{}) term.FgBgColor { 291 for i := 0; i < len(keyvals)-1; i += 2 { 292 if keyvals[i] == "validator" { 293 return term.FgBgColor{Fg: term.Color(uint8(keyvals[i+1].(int) + 1))} 294 } 295 } 296 return term.FgBgColor{} 297 }) 298 } 299 300 // connect N mempool reactors through N switches 301 func makeAndConnectReactors(config *cfg.Config, n int) []*Reactor { 302 reactors := make([]*Reactor, n) 303 logger := mempoolLogger() 304 for i := 0; i < n; i++ { 305 app := kvstore.NewApplication() 306 cc := proxy.NewLocalClientCreator(app) 307 mempool, cleanup := newMempoolWithApp(cc) 308 defer cleanup() 309 310 reactors[i] = NewReactor(config.Mempool, mempool) // so we dont start the consensus states 311 reactors[i].SetLogger(logger.With("validator", i)) 312 } 313 314 p2p.MakeConnectedSwitches(config.P2P, n, func(i int, s *p2p.Switch) *p2p.Switch { 315 s.AddReactor("MEMPOOL", reactors[i]) 316 return s 317 318 }, p2p.Connect2Switches) 319 return reactors 320 } 321 322 func waitForTxsOnReactors(t *testing.T, txs types.Txs, reactors []*Reactor) { 323 // wait for the txs in all mempools 324 wg := new(sync.WaitGroup) 325 for i, reactor := range reactors { 326 wg.Add(1) 327 go func(r *Reactor, reactorIndex int) { 328 defer wg.Done() 329 waitForTxsOnReactor(t, txs, r, reactorIndex) 330 }(reactor, i) 331 } 332 333 done := make(chan struct{}) 334 go func() { 335 wg.Wait() 336 close(done) 337 }() 338 339 timer := time.After(timeout) 340 select { 341 case <-timer: 342 t.Fatal("Timed out waiting for txs") 343 case <-done: 344 } 345 } 346 347 func waitForTxsOnReactor(t *testing.T, txs types.Txs, reactor *Reactor, reactorIndex int) { 348 mempool := reactor.mempool 349 for mempool.Size() < len(txs) { 350 time.Sleep(time.Millisecond * 100) 351 } 352 353 reapedTxs := mempool.ReapMaxTxs(len(txs)) 354 for i, tx := range txs { 355 assert.Equalf(t, tx, reapedTxs[i], 356 "txs at index %d on reactor %d don't match: %v vs %v", i, reactorIndex, tx, reapedTxs[i]) 357 } 358 } 359 360 // ensure no txs on reactor after some timeout 361 func ensureNoTxs(t *testing.T, reactor *Reactor, timeout time.Duration) { 362 time.Sleep(timeout) // wait for the txs in all mempools 363 assert.Zero(t, reactor.mempool.Size()) 364 } 365 366 func TestMempoolVectors(t *testing.T) { 367 testCases := []struct { 368 testName string 369 tx []byte 370 expBytes string 371 }{ 372 {"tx 1", []byte{123}, "0a030a017b"}, 373 {"tx 2", []byte("proto encoding in mempool"), "0a1b0a1970726f746f20656e636f64696e6720696e206d656d706f6f6c"}, 374 } 375 376 for _, tc := range testCases { 377 tc := tc 378 379 msg := memproto.Message{ 380 Sum: &memproto.Message_Txs{ 381 Txs: &memproto.Txs{Txs: [][]byte{tc.tx}}, 382 }, 383 } 384 bz, err := msg.Marshal() 385 require.NoError(t, err, tc.testName) 386 387 require.Equal(t, tc.expBytes, hex.EncodeToString(bz), tc.testName) 388 } 389 }