github.com/okex/exchain@v1.8.0/libs/tendermint/consensus/reactor_test.go (about) 1 package consensus 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "path" 8 "runtime" 9 "runtime/pprof" 10 "sync" 11 "testing" 12 "time" 13 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 17 dbm "github.com/okex/exchain/libs/tm-db" 18 19 abcicli "github.com/okex/exchain/libs/tendermint/abci/client" 20 "github.com/okex/exchain/libs/tendermint/abci/example/kvstore" 21 abci "github.com/okex/exchain/libs/tendermint/abci/types" 22 cfg "github.com/okex/exchain/libs/tendermint/config" 23 cstypes "github.com/okex/exchain/libs/tendermint/consensus/types" 24 "github.com/okex/exchain/libs/tendermint/crypto/tmhash" 25 "github.com/okex/exchain/libs/tendermint/libs/bits" 26 "github.com/okex/exchain/libs/tendermint/libs/bytes" 27 "github.com/okex/exchain/libs/tendermint/libs/log" 28 mempl "github.com/okex/exchain/libs/tendermint/mempool" 29 "github.com/okex/exchain/libs/tendermint/p2p" 30 "github.com/okex/exchain/libs/tendermint/p2p/mock" 31 sm "github.com/okex/exchain/libs/tendermint/state" 32 "github.com/okex/exchain/libs/tendermint/store" 33 "github.com/okex/exchain/libs/tendermint/types" 34 ) 35 36 //---------------------------------------------- 37 // in-process testnets 38 39 func startConsensusNet(t *testing.T, css []*State, n int) ( 40 []*Reactor, 41 []types.Subscription, 42 []*types.EventBus, 43 ) { 44 reactors := make([]*Reactor, n) 45 blocksSubs := make([]types.Subscription, 0) 46 eventBuses := make([]*types.EventBus, n) 47 for i := 0; i < n; i++ { 48 /*logger, err := tmflags.ParseLogLevel("consensus:info,*:error", logger, "info") 49 if err != nil { t.Fatal(err)}*/ 50 reactors[i] = NewReactor(css[i], true, false) // so we dont start the consensus states 51 reactors[i].SetLogger(css[i].Logger) 52 53 // eventBus is already started with the cs 54 eventBuses[i] = css[i].eventBus 55 reactors[i].SetEventBus(eventBuses[i]) 56 57 blocksSub, err := eventBuses[i].Subscribe(context.Background(), testSubscriber, types.EventQueryNewBlock) 58 require.NoError(t, err) 59 blocksSubs = append(blocksSubs, blocksSub) 60 61 if css[i].state.LastBlockHeight == 0 { //simulate handle initChain in handshake 62 sm.SaveState(css[i].blockExec.DB(), css[i].state) 63 } 64 } 65 // make connected switches and start all reactors 66 p2p.MakeConnectedSwitches(config.P2P, n, func(i int, s *p2p.Switch) *p2p.Switch { 67 s.AddReactor("CONSENSUS", reactors[i]) 68 s.SetLogger(reactors[i].conS.Logger.With("module", "p2p")) 69 return s 70 }, p2p.Connect2Switches) 71 72 // now that everyone is connected, start the state machines 73 // If we started the state machines before everyone was connected, 74 // we'd block when the cs fires NewBlockEvent and the peers are trying to start their reactors 75 // TODO: is this still true with new pubsub? 76 for i := 0; i < n; i++ { 77 s := reactors[i].conS.GetState() 78 reactors[i].SwitchToConsensus(s, 0) 79 } 80 return reactors, blocksSubs, eventBuses 81 } 82 83 func stopConsensusNet(logger log.Logger, reactors []*Reactor, eventBuses []*types.EventBus) { 84 logger.Info("stopConsensusNet", "n", len(reactors)) 85 for i, r := range reactors { 86 logger.Info("stopConsensusNet: Stopping Reactor", "i", i) 87 r.Switch.Stop() 88 } 89 for i, b := range eventBuses { 90 logger.Info("stopConsensusNet: Stopping eventBus", "i", i) 91 b.Stop() 92 } 93 logger.Info("stopConsensusNet: DONE", "n", len(reactors)) 94 } 95 96 // Ensure a testnet makes blocks 97 func TestReactorBasic(t *testing.T) { 98 N := 4 99 css, cleanup := randConsensusNet(N, "consensus_reactor_test", newMockTickerFunc(true), newCounter) 100 defer cleanup() 101 reactors, blocksSubs, eventBuses := startConsensusNet(t, css, N) 102 defer stopConsensusNet(log.TestingLogger(), reactors, eventBuses) 103 // wait till everyone makes the first new block 104 timeoutWaitGroup(t, N, func(j int) { 105 <-blocksSubs[j].Out() 106 }, css) 107 } 108 109 // Ensure we can process blocks with evidence 110 func TestReactorWithEvidence(t *testing.T) { 111 types.RegisterMockEvidences(cdc) 112 types.RegisterMockEvidences(types.GetCodec()) 113 114 nValidators := 4 115 testName := "consensus_reactor_test" 116 tickerFunc := newMockTickerFunc(true) 117 appFunc := newCounter 118 119 // heed the advice from https://www.sandimetz.com/blog/2016/1/20/the-wrong-abstraction 120 // to unroll unwieldy abstractions. Here we duplicate the code from: 121 // css := randConsensusNet(N, "consensus_reactor_test", newMockTickerFunc(true), newCounter) 122 123 genDoc, privVals := randGenesisDoc(nValidators, false, 30) 124 css := make([]*State, nValidators) 125 logger := consensusLogger() 126 for i := 0; i < nValidators; i++ { 127 stateDB := dbm.NewMemDB() // each state needs its own db 128 state, _ := sm.LoadStateFromDBOrGenesisDoc(stateDB, genDoc) 129 thisConfig := ResetConfig(fmt.Sprintf("%s_%d", testName, i)) 130 defer os.RemoveAll(thisConfig.RootDir) 131 ensureDir(path.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal 132 app := appFunc() 133 vals := types.TM2PB.ValidatorUpdates(state.Validators) 134 app.InitChain(abci.RequestInitChain{Validators: vals}) 135 136 pv := privVals[i] 137 // duplicate code from: 138 // css[i] = newStateWithConfig(thisConfig, state, privVals[i], app) 139 140 blockDB := dbm.NewMemDB() 141 blockStore := store.NewBlockStore(blockDB) 142 143 // one for mempool, one for consensus 144 mtx := new(sync.Mutex) 145 proxyAppConnMem := abcicli.NewLocalClient(mtx, app) 146 proxyAppConnCon := abcicli.NewLocalClient(mtx, app) 147 148 // Make Mempool 149 mempool := mempl.NewCListMempool(thisConfig.Mempool, proxyAppConnMem, 0) 150 mempool.SetLogger(log.TestingLogger().With("module", "mempool")) 151 if thisConfig.Consensus.WaitForTxs() { 152 mempool.EnableTxsAvailable() 153 } 154 155 // mock the evidence pool 156 // everyone includes evidence of another double signing 157 vIdx := (i + 1) % nValidators 158 pubKey, err := privVals[vIdx].GetPubKey() 159 require.NoError(t, err) 160 evpool := newMockEvidencePool(pubKey.Address()) 161 162 // Make State 163 blockExec := sm.NewBlockExecutor(stateDB, log.TestingLogger(), proxyAppConnCon, mempool, evpool) 164 cs := NewState(thisConfig.Consensus, state, blockExec, blockStore, mempool, evpool) 165 cs.SetLogger(log.TestingLogger().With("module", "consensus")) 166 cs.SetPrivValidator(pv) 167 168 eventBus := types.NewEventBus() 169 eventBus.SetLogger(log.TestingLogger().With("module", "events")) 170 eventBus.Start() 171 cs.SetEventBus(eventBus) 172 173 cs.SetTimeoutTicker(tickerFunc()) 174 cs.SetLogger(logger.With("validator", i, "module", "consensus")) 175 176 css[i] = cs 177 } 178 179 reactors, blocksSubs, eventBuses := startConsensusNet(t, css, nValidators) 180 defer stopConsensusNet(log.TestingLogger(), reactors, eventBuses) 181 182 // wait till everyone makes the first new block with no evidence 183 timeoutWaitGroup(t, nValidators, func(j int) { 184 msg := <-blocksSubs[j].Out() 185 block := msg.Data().(types.EventDataNewBlock).Block 186 assert.True(t, len(block.Evidence.Evidence) == 0) 187 }, css) 188 189 // second block should have evidence 190 timeoutWaitGroup(t, nValidators, func(j int) { 191 msg := <-blocksSubs[j].Out() 192 block := msg.Data().(types.EventDataNewBlock).Block 193 assert.True(t, len(block.Evidence.Evidence) > 0) 194 }, css) 195 } 196 197 // mock evidence pool returns no evidence for block 1, 198 // and returnes one piece for all higher blocks. The one piece 199 // is for a given validator at block 1. 200 type mockEvidencePool struct { 201 height int 202 ev []types.Evidence 203 } 204 205 func newMockEvidencePool(val []byte) *mockEvidencePool { 206 return &mockEvidencePool{ 207 ev: []types.Evidence{types.NewMockEvidence(1, time.Now().UTC(), 1, val)}, 208 } 209 } 210 211 // NOTE: maxBytes is ignored 212 func (m *mockEvidencePool) PendingEvidence(maxBytes int64) []types.Evidence { 213 if m.height > 0 { 214 return m.ev 215 } 216 return nil 217 } 218 func (m *mockEvidencePool) AddEvidence(types.Evidence) error { return nil } 219 func (m *mockEvidencePool) Update(block *types.Block, state sm.State) { 220 if m.height > 0 { 221 if len(block.Evidence.Evidence) == 0 { 222 panic("block has no evidence") 223 } 224 } 225 m.height++ 226 } 227 func (m *mockEvidencePool) IsCommitted(types.Evidence) bool { return false } 228 229 //------------------------------------ 230 231 // Ensure a testnet makes blocks when there are txs 232 func TestReactorCreatesBlockWhenEmptyBlocksFalse(t *testing.T) { 233 N := 4 234 css, cleanup := randConsensusNet(N, "consensus_reactor_test", newMockTickerFunc(true), newCounter, 235 func(c *cfg.Config) { 236 c.Consensus.CreateEmptyBlocks = false 237 }) 238 defer cleanup() 239 reactors, blocksSubs, eventBuses := startConsensusNet(t, css, N) 240 defer stopConsensusNet(log.TestingLogger(), reactors, eventBuses) 241 242 // send a tx 243 if err := assertMempool(css[3].txNotifier).CheckTx([]byte{1, 2, 3}, nil, mempl.TxInfo{}); err != nil { 244 t.Error(err) 245 } 246 247 // wait till everyone makes the first new block 248 timeoutWaitGroup(t, N, func(j int) { 249 <-blocksSubs[j].Out() 250 }, css) 251 } 252 253 func TestReactorReceiveDoesNotPanicIfAddPeerHasntBeenCalledYet(t *testing.T) { 254 N := 1 255 css, cleanup := randConsensusNet(N, "consensus_reactor_test", newMockTickerFunc(true), newCounter) 256 defer cleanup() 257 reactors, _, eventBuses := startConsensusNet(t, css, N) 258 defer stopConsensusNet(log.TestingLogger(), reactors, eventBuses) 259 260 var ( 261 reactor = reactors[0] 262 peer = mock.NewPeer(nil) 263 msg = cdc.MustMarshalBinaryBare(&HasVoteMessage{Height: 1, Round: 1, Index: 1, Type: types.PrevoteType}) 264 ) 265 266 reactor.InitPeer(peer) 267 268 // simulate switch calling Receive before AddPeer 269 assert.NotPanics(t, func() { 270 reactor.Receive(StateChannel, peer, msg) 271 reactor.AddPeer(peer) 272 }) 273 } 274 275 func TestReactorReceivePanicsIfInitPeerHasntBeenCalledYet(t *testing.T) { 276 N := 1 277 css, cleanup := randConsensusNet(N, "consensus_reactor_test", newMockTickerFunc(true), newCounter) 278 defer cleanup() 279 reactors, _, eventBuses := startConsensusNet(t, css, N) 280 defer stopConsensusNet(log.TestingLogger(), reactors, eventBuses) 281 282 var ( 283 reactor = reactors[0] 284 peer = mock.NewPeer(nil) 285 msg = cdc.MustMarshalBinaryBare(&HasVoteMessage{Height: 1, Round: 1, Index: 1, Type: types.PrevoteType}) 286 ) 287 288 // we should call InitPeer here 289 290 // simulate switch calling Receive before AddPeer 291 assert.Panics(t, func() { 292 reactor.Receive(StateChannel, peer, msg) 293 }) 294 } 295 296 // Test we record stats about votes and block parts from other peers. 297 func TestReactorRecordsVotesAndBlockParts(t *testing.T) { 298 N := 4 299 css, cleanup := randConsensusNet(N, "consensus_reactor_test", newMockTickerFunc(true), newCounter) 300 defer cleanup() 301 reactors, blocksSubs, eventBuses := startConsensusNet(t, css, N) 302 defer stopConsensusNet(log.TestingLogger(), reactors, eventBuses) 303 304 // wait till everyone makes the first new block 305 timeoutWaitGroup(t, N, func(j int) { 306 <-blocksSubs[j].Out() 307 }, css) 308 309 // Get peer 310 peer := reactors[1].Switch.Peers().List()[0] 311 // Get peer state 312 ps := peer.Get(types.PeerStateKey).(*PeerState) 313 314 assert.Equal(t, true, ps.VotesSent() > 0, "number of votes sent should have increased") 315 assert.Equal(t, true, ps.BlockPartsSent() > 0, "number of votes sent should have increased") 316 } 317 318 //------------------------------------------------------------- 319 // ensure we can make blocks despite cycling a validator set 320 321 func TestReactorVotingPowerChange(t *testing.T) { 322 nVals := 4 323 logger := log.TestingLogger() 324 css, cleanup := randConsensusNet( 325 nVals, 326 "consensus_voting_power_changes_test", 327 newMockTickerFunc(true), 328 newPersistentKVStore) 329 defer cleanup() 330 reactors, blocksSubs, eventBuses := startConsensusNet(t, css, nVals) 331 defer stopConsensusNet(logger, reactors, eventBuses) 332 333 // map of active validators 334 activeVals := make(map[string]struct{}) 335 for i := 0; i < nVals; i++ { 336 pubKey, err := css[i].privValidator.GetPubKey() 337 require.NoError(t, err) 338 addr := pubKey.Address() 339 activeVals[string(addr)] = struct{}{} 340 } 341 342 // wait till everyone makes block 1 343 timeoutWaitGroup(t, nVals, func(j int) { 344 <-blocksSubs[j].Out() 345 }, css) 346 347 //--------------------------------------------------------------------------- 348 logger.Debug("---------------------------- Testing changing the voting power of one validator a few times") 349 350 val1PubKey, err := css[0].privValidator.GetPubKey() 351 require.NoError(t, err) 352 val1PubKeyABCI := types.TM2PB.PubKey(val1PubKey) 353 updateValidatorTx := kvstore.MakeValSetChangeTx(val1PubKeyABCI, 25) 354 previousTotalVotingPower := css[0].GetRoundState().LastValidators.TotalVotingPower() 355 356 waitForAndValidateBlock(t, nVals, activeVals, blocksSubs, css, updateValidatorTx) 357 waitForAndValidateBlockWithTx(t, nVals, activeVals, blocksSubs, css, updateValidatorTx) 358 waitForAndValidateBlock(t, nVals, activeVals, blocksSubs, css) 359 waitForAndValidateBlock(t, nVals, activeVals, blocksSubs, css) 360 361 if css[0].GetRoundState().LastValidators.TotalVotingPower() == previousTotalVotingPower { 362 t.Fatalf( 363 "expected voting power to change (before: %d, after: %d)", 364 previousTotalVotingPower, 365 css[0].GetRoundState().LastValidators.TotalVotingPower()) 366 } 367 368 updateValidatorTx = kvstore.MakeValSetChangeTx(val1PubKeyABCI, 2) 369 previousTotalVotingPower = css[0].GetRoundState().LastValidators.TotalVotingPower() 370 371 waitForAndValidateBlock(t, nVals, activeVals, blocksSubs, css, updateValidatorTx) 372 waitForAndValidateBlockWithTx(t, nVals, activeVals, blocksSubs, css, updateValidatorTx) 373 waitForAndValidateBlock(t, nVals, activeVals, blocksSubs, css) 374 waitForAndValidateBlock(t, nVals, activeVals, blocksSubs, css) 375 376 if css[0].GetRoundState().LastValidators.TotalVotingPower() == previousTotalVotingPower { 377 t.Fatalf( 378 "expected voting power to change (before: %d, after: %d)", 379 previousTotalVotingPower, 380 css[0].GetRoundState().LastValidators.TotalVotingPower()) 381 } 382 383 updateValidatorTx = kvstore.MakeValSetChangeTx(val1PubKeyABCI, 26) 384 previousTotalVotingPower = css[0].GetRoundState().LastValidators.TotalVotingPower() 385 386 waitForAndValidateBlock(t, nVals, activeVals, blocksSubs, css, updateValidatorTx) 387 waitForAndValidateBlockWithTx(t, nVals, activeVals, blocksSubs, css, updateValidatorTx) 388 waitForAndValidateBlock(t, nVals, activeVals, blocksSubs, css) 389 waitForAndValidateBlock(t, nVals, activeVals, blocksSubs, css) 390 391 if css[0].GetRoundState().LastValidators.TotalVotingPower() == previousTotalVotingPower { 392 t.Fatalf( 393 "expected voting power to change (before: %d, after: %d)", 394 previousTotalVotingPower, 395 css[0].GetRoundState().LastValidators.TotalVotingPower()) 396 } 397 } 398 399 func TestReactorValidatorSetChanges(t *testing.T) { 400 return 401 nPeers := 7 402 nVals := 4 403 css, _, _, cleanup := randConsensusNetWithPeers( 404 nVals, 405 nPeers, 406 "consensus_val_set_changes_test", 407 newMockTickerFunc(true), 408 newPersistentKVStoreWithPath) 409 410 defer cleanup() 411 logger := log.TestingLogger() 412 413 reactors, blocksSubs, eventBuses := startConsensusNet(t, css, nPeers) 414 defer stopConsensusNet(logger, reactors, eventBuses) 415 416 // map of active validators 417 activeVals := make(map[string]struct{}) 418 for i := 0; i < nVals; i++ { 419 pubKey, err := css[i].privValidator.GetPubKey() 420 require.NoError(t, err) 421 activeVals[string(pubKey.Address())] = struct{}{} 422 } 423 424 // wait till everyone makes block 1 425 timeoutWaitGroup(t, nPeers, func(j int) { 426 <-blocksSubs[j].Out() 427 }, css) 428 429 //--------------------------------------------------------------------------- 430 logger.Info("---------------------------- Testing adding one validator") 431 432 newValidatorPubKey1, err := css[nVals].privValidator.GetPubKey() 433 require.NoError(t, err) 434 valPubKey1ABCI := types.TM2PB.PubKey(newValidatorPubKey1) 435 newValidatorTx1 := kvstore.MakeValSetChangeTx(valPubKey1ABCI, testMinPower) 436 437 // wait till everyone makes block 2 438 // ensure the commit includes all validators 439 // send newValTx to change vals in block 3 440 waitForAndValidateBlock(t, nPeers, activeVals, blocksSubs, css, newValidatorTx1) 441 442 // wait till everyone makes block 3. 443 // it includes the commit for block 2, which is by the original validator set 444 waitForAndValidateBlockWithTx(t, nPeers, activeVals, blocksSubs, css, newValidatorTx1) 445 446 // wait till everyone makes block 4. 447 // it includes the commit for block 3, which is by the original validator set 448 waitForAndValidateBlock(t, nPeers, activeVals, blocksSubs, css) 449 450 // the commits for block 4 should be with the updated validator set 451 activeVals[string(newValidatorPubKey1.Address())] = struct{}{} 452 453 // wait till everyone makes block 5 454 // it includes the commit for block 4, which should have the updated validator set 455 waitForBlockWithUpdatedValsAndValidateIt(t, nPeers, activeVals, blocksSubs, css) 456 457 //--------------------------------------------------------------------------- 458 logger.Info("---------------------------- Testing changing the voting power of one validator") 459 460 updateValidatorPubKey1, err := css[nVals].privValidator.GetPubKey() 461 require.NoError(t, err) 462 updatePubKey1ABCI := types.TM2PB.PubKey(updateValidatorPubKey1) 463 updateValidatorTx1 := kvstore.MakeValSetChangeTx(updatePubKey1ABCI, 25) 464 previousTotalVotingPower := css[nVals].GetRoundState().LastValidators.TotalVotingPower() 465 466 waitForAndValidateBlock(t, nPeers, activeVals, blocksSubs, css, updateValidatorTx1) 467 waitForAndValidateBlockWithTx(t, nPeers, activeVals, blocksSubs, css, updateValidatorTx1) 468 waitForAndValidateBlock(t, nPeers, activeVals, blocksSubs, css) 469 waitForBlockWithUpdatedValsAndValidateIt(t, nPeers, activeVals, blocksSubs, css) 470 471 if css[nVals].GetRoundState().LastValidators.TotalVotingPower() == previousTotalVotingPower { 472 t.Errorf( 473 "expected voting power to change (before: %d, after: %d)", 474 previousTotalVotingPower, 475 css[nVals].GetRoundState().LastValidators.TotalVotingPower()) 476 } 477 478 //--------------------------------------------------------------------------- 479 logger.Info("---------------------------- Testing adding two validators at once") 480 481 newValidatorPubKey2, err := css[nVals+1].privValidator.GetPubKey() 482 require.NoError(t, err) 483 newVal2ABCI := types.TM2PB.PubKey(newValidatorPubKey2) 484 newValidatorTx2 := kvstore.MakeValSetChangeTx(newVal2ABCI, testMinPower) 485 486 newValidatorPubKey3, err := css[nVals+2].privValidator.GetPubKey() 487 require.NoError(t, err) 488 newVal3ABCI := types.TM2PB.PubKey(newValidatorPubKey3) 489 newValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, testMinPower) 490 491 waitForAndValidateBlock(t, nPeers, activeVals, blocksSubs, css, newValidatorTx2, newValidatorTx3) 492 waitForAndValidateBlockWithTx(t, nPeers, activeVals, blocksSubs, css, newValidatorTx2, newValidatorTx3) 493 waitForAndValidateBlock(t, nPeers, activeVals, blocksSubs, css) 494 activeVals[string(newValidatorPubKey2.Address())] = struct{}{} 495 activeVals[string(newValidatorPubKey3.Address())] = struct{}{} 496 waitForBlockWithUpdatedValsAndValidateIt(t, nPeers, activeVals, blocksSubs, css) 497 498 //--------------------------------------------------------------------------- 499 logger.Info("---------------------------- Testing removing two validators at once") 500 501 removeValidatorTx2 := kvstore.MakeValSetChangeTx(newVal2ABCI, 0) 502 removeValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, 0) 503 504 waitForAndValidateBlock(t, nPeers, activeVals, blocksSubs, css, removeValidatorTx2, removeValidatorTx3) 505 waitForAndValidateBlockWithTx(t, nPeers, activeVals, blocksSubs, css, removeValidatorTx2, removeValidatorTx3) 506 waitForAndValidateBlock(t, nPeers, activeVals, blocksSubs, css) 507 delete(activeVals, string(newValidatorPubKey2.Address())) 508 delete(activeVals, string(newValidatorPubKey3.Address())) 509 waitForBlockWithUpdatedValsAndValidateIt(t, nPeers, activeVals, blocksSubs, css) 510 } 511 512 // Check we can make blocks with skip_timeout_commit=false 513 func TestReactorWithTimeoutCommit(t *testing.T) { 514 N := 4 515 css, cleanup := randConsensusNet(N, "consensus_reactor_with_timeout_commit_test", newMockTickerFunc(false), newCounter) 516 defer cleanup() 517 // override default SkipTimeoutCommit == true for tests 518 for i := 0; i < N; i++ { 519 css[i].config.SkipTimeoutCommit = false 520 } 521 522 reactors, blocksSubs, eventBuses := startConsensusNet(t, css, N-1) 523 defer stopConsensusNet(log.TestingLogger(), reactors, eventBuses) 524 525 // wait till everyone makes the first new block 526 timeoutWaitGroup(t, N-1, func(j int) { 527 <-blocksSubs[j].Out() 528 }, css) 529 } 530 531 func waitForAndValidateBlock( 532 t *testing.T, 533 n int, 534 activeVals map[string]struct{}, 535 blocksSubs []types.Subscription, 536 css []*State, 537 txs ...[]byte, 538 ) { 539 timeoutWaitGroup(t, n, func(j int) { 540 css[j].Logger.Debug("waitForAndValidateBlock") 541 msg := <-blocksSubs[j].Out() 542 newBlock := msg.Data().(types.EventDataNewBlock).Block 543 css[j].Logger.Debug("waitForAndValidateBlock: Got block", "height", newBlock.Height) 544 err := validateBlock(newBlock, activeVals) 545 assert.Nil(t, err) 546 for _, tx := range txs { 547 err := assertMempool(css[j].txNotifier).CheckTx(tx, nil, mempl.TxInfo{}) 548 assert.Nil(t, err) 549 } 550 }, css) 551 } 552 553 func waitForAndValidateBlockWithTx( 554 t *testing.T, 555 n int, 556 activeVals map[string]struct{}, 557 blocksSubs []types.Subscription, 558 css []*State, 559 txs ...[]byte, 560 ) { 561 timeoutWaitGroup(t, n, func(j int) { 562 ntxs := 0 563 BLOCK_TX_LOOP: 564 for { 565 css[j].Logger.Debug("waitForAndValidateBlockWithTx", "ntxs", ntxs) 566 msg := <-blocksSubs[j].Out() 567 newBlock := msg.Data().(types.EventDataNewBlock).Block 568 css[j].Logger.Debug("waitForAndValidateBlockWithTx: Got block", "height", newBlock.Height) 569 err := validateBlock(newBlock, activeVals) 570 assert.Nil(t, err) 571 572 // check that txs match the txs we're waiting for. 573 // note they could be spread over multiple blocks, 574 // but they should be in order. 575 for _, tx := range newBlock.Data.Txs { 576 assert.EqualValues(t, txs[ntxs], tx) 577 ntxs++ 578 } 579 580 if ntxs == len(txs) { 581 break BLOCK_TX_LOOP 582 } 583 } 584 585 }, css) 586 } 587 588 func waitForBlockWithUpdatedValsAndValidateIt( 589 t *testing.T, 590 n int, 591 updatedVals map[string]struct{}, 592 blocksSubs []types.Subscription, 593 css []*State, 594 ) { 595 timeoutWaitGroup(t, n, func(j int) { 596 597 var newBlock *types.Block 598 LOOP: 599 for { 600 css[j].Logger.Debug("waitForBlockWithUpdatedValsAndValidateIt") 601 msg := <-blocksSubs[j].Out() 602 newBlock = msg.Data().(types.EventDataNewBlock).Block 603 if newBlock.LastCommit.Size() == len(updatedVals) { 604 css[j].Logger.Debug("waitForBlockWithUpdatedValsAndValidateIt: Got block", "height", newBlock.Height) 605 break LOOP 606 } else { 607 css[j].Logger.Debug( 608 "waitForBlockWithUpdatedValsAndValidateIt: Got block with no new validators. Skipping", 609 "height", 610 newBlock.Height) 611 } 612 } 613 614 err := validateBlock(newBlock, updatedVals) 615 assert.Nil(t, err) 616 }, css) 617 } 618 619 // expects high synchrony! 620 func validateBlock(block *types.Block, activeVals map[string]struct{}) error { 621 if block.LastCommit.Size() != len(activeVals) { 622 return fmt.Errorf( 623 "commit size doesn't match number of active validators. Got %d, expected %d", 624 block.LastCommit.Size(), 625 len(activeVals)) 626 } 627 628 for _, commitSig := range block.LastCommit.Signatures { 629 if _, ok := activeVals[string(commitSig.ValidatorAddress)]; !ok { 630 return fmt.Errorf("found vote for inactive validator %X", commitSig.ValidatorAddress) 631 } 632 } 633 return nil 634 } 635 636 func timeoutWaitGroup(t *testing.T, n int, f func(int), css []*State) { 637 wg := new(sync.WaitGroup) 638 wg.Add(n) 639 for i := 0; i < n; i++ { 640 go func(j int) { 641 f(j) 642 wg.Done() 643 }(i) 644 } 645 646 done := make(chan struct{}) 647 go func() { 648 wg.Wait() 649 close(done) 650 }() 651 652 // we're running many nodes in-process, possibly in in a virtual machine, 653 // and spewing debug messages - making a block could take a while, 654 timeout := time.Second * 300 655 656 select { 657 case <-done: 658 case <-time.After(timeout): 659 for i, cs := range css { 660 t.Log("#################") 661 t.Log("Validator", i) 662 t.Log(cs.GetRoundState()) 663 t.Log("") 664 } 665 os.Stdout.Write([]byte("pprof.Lookup('goroutine'):\n")) 666 pprof.Lookup("goroutine").WriteTo(os.Stdout, 1) 667 capture() 668 panic("Timed out waiting for all validators to commit a block") 669 } 670 } 671 672 func capture() { 673 trace := make([]byte, 10240000) 674 count := runtime.Stack(trace, true) 675 fmt.Printf("Stack of %d bytes: %s\n", count, trace) 676 } 677 678 //------------------------------------------------------------- 679 // Ensure basic validation of structs is functioning 680 681 func TestNewRoundStepMessageValidateBasic(t *testing.T) { 682 testCases := []struct { // nolint: maligned 683 expectErr bool 684 messageRound int 685 messageLastCommitRound int 686 messageHeight int64 687 testName string 688 messageStep cstypes.RoundStepType 689 }{ 690 {false, 0, 0, 0, "Valid Message", 0x01}, 691 {true, -1, 0, 0, "Invalid Message", 0x01}, 692 {true, 0, 0, -1, "Invalid Message", 0x01}, 693 {true, 0, 0, 1, "Invalid Message", 0x00}, 694 {true, 0, 0, 1, "Invalid Message", 0x00}, 695 {true, 0, -2, 2, "Invalid Message", 0x01}, 696 } 697 698 for _, tc := range testCases { 699 tc := tc 700 t.Run(tc.testName, func(t *testing.T) { 701 message := NewRoundStepMessage{ 702 Height: tc.messageHeight, 703 Round: tc.messageRound, 704 Step: tc.messageStep, 705 LastCommitRound: tc.messageLastCommitRound, 706 } 707 708 assert.Equal(t, tc.expectErr, message.ValidateBasic() != nil, "Validate Basic had an unexpected result") 709 }) 710 } 711 } 712 713 func TestNewValidBlockMessageValidateBasic(t *testing.T) { 714 testCases := []struct { 715 malleateFn func(*NewValidBlockMessage) 716 expErr string 717 }{ 718 {func(msg *NewValidBlockMessage) {}, ""}, 719 {func(msg *NewValidBlockMessage) { msg.Height = -1 }, "negative Height"}, 720 {func(msg *NewValidBlockMessage) { msg.Round = -1 }, "negative Round"}, 721 { 722 func(msg *NewValidBlockMessage) { msg.BlockPartsHeader.Total = 2 }, 723 "blockParts bit array size 1 not equal to BlockPartsHeader.Total 2", 724 }, 725 { 726 func(msg *NewValidBlockMessage) { msg.BlockPartsHeader.Total = 0; msg.BlockParts = bits.NewBitArray(0) }, 727 "empty blockParts", 728 }, 729 { 730 func(msg *NewValidBlockMessage) { msg.BlockParts = bits.NewBitArray(types.MaxBlockPartsCount + 1) }, 731 "blockParts bit array size 1602 not equal to BlockPartsHeader.Total 1", 732 }, 733 } 734 735 for i, tc := range testCases { 736 tc := tc 737 t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) { 738 msg := &NewValidBlockMessage{ 739 Height: 1, 740 Round: 0, 741 BlockPartsHeader: types.PartSetHeader{ 742 Total: 1, 743 }, 744 BlockParts: bits.NewBitArray(1), 745 } 746 747 tc.malleateFn(msg) 748 err := msg.ValidateBasic() 749 if tc.expErr != "" && assert.Error(t, err) { 750 assert.Contains(t, err.Error(), tc.expErr) 751 } 752 }) 753 } 754 } 755 756 func TestProposalPOLMessageValidateBasic(t *testing.T) { 757 testCases := []struct { 758 malleateFn func(*ProposalPOLMessage) 759 expErr string 760 }{ 761 {func(msg *ProposalPOLMessage) {}, ""}, 762 {func(msg *ProposalPOLMessage) { msg.Height = -1 }, "negative Height"}, 763 {func(msg *ProposalPOLMessage) { msg.ProposalPOLRound = -1 }, "negative ProposalPOLRound"}, 764 {func(msg *ProposalPOLMessage) { msg.ProposalPOL = bits.NewBitArray(0) }, "empty ProposalPOL bit array"}, 765 {func(msg *ProposalPOLMessage) { msg.ProposalPOL = bits.NewBitArray(types.MaxVotesCount + 1) }, 766 "ProposalPOL bit array is too big: 10001, max: 10000"}, 767 } 768 769 for i, tc := range testCases { 770 tc := tc 771 t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) { 772 msg := &ProposalPOLMessage{ 773 Height: 1, 774 ProposalPOLRound: 1, 775 ProposalPOL: bits.NewBitArray(1), 776 } 777 778 tc.malleateFn(msg) 779 err := msg.ValidateBasic() 780 if tc.expErr != "" && assert.Error(t, err) { 781 assert.Contains(t, err.Error(), tc.expErr) 782 } 783 }) 784 } 785 } 786 787 func TestBlockPartMessageValidateBasic(t *testing.T) { 788 testPart := new(types.Part) 789 testPart.Proof.LeafHash = tmhash.Sum([]byte("leaf")) 790 testCases := []struct { 791 testName string 792 messageHeight int64 793 messageRound int 794 messagePart *types.Part 795 expectErr bool 796 }{ 797 {"Valid Message", 0, 0, testPart, false}, 798 {"Invalid Message", -1, 0, testPart, true}, 799 {"Invalid Message", 0, -1, testPart, true}, 800 } 801 802 for _, tc := range testCases { 803 tc := tc 804 t.Run(tc.testName, func(t *testing.T) { 805 message := BlockPartMessage{ 806 Height: tc.messageHeight, 807 Round: tc.messageRound, 808 Part: tc.messagePart, 809 } 810 811 assert.Equal(t, tc.expectErr, message.ValidateBasic() != nil, "Validate Basic had an unexpected result") 812 }) 813 } 814 815 message := BlockPartMessage{Height: 0, Round: 0, Part: new(types.Part)} 816 message.Part.Index = -1 817 818 assert.Equal(t, true, message.ValidateBasic() != nil, "Validate Basic had an unexpected result") 819 } 820 821 func TestHasVoteMessageValidateBasic(t *testing.T) { 822 const ( 823 validSignedMsgType types.SignedMsgType = 0x01 824 invalidSignedMsgType types.SignedMsgType = 0x03 825 ) 826 827 testCases := []struct { // nolint: maligned 828 expectErr bool 829 messageRound int 830 messageIndex int 831 messageHeight int64 832 testName string 833 messageType types.SignedMsgType 834 }{ 835 {false, 0, 0, 0, "Valid Message", validSignedMsgType}, 836 {true, -1, 0, 0, "Invalid Message", validSignedMsgType}, 837 {true, 0, -1, 0, "Invalid Message", validSignedMsgType}, 838 {true, 0, 0, 0, "Invalid Message", invalidSignedMsgType}, 839 {true, 0, 0, -1, "Invalid Message", validSignedMsgType}, 840 } 841 842 for _, tc := range testCases { 843 tc := tc 844 t.Run(tc.testName, func(t *testing.T) { 845 message := HasVoteMessage{ 846 Height: tc.messageHeight, 847 Round: tc.messageRound, 848 Type: tc.messageType, 849 Index: tc.messageIndex, 850 } 851 852 assert.Equal(t, tc.expectErr, message.ValidateBasic() != nil, "Validate Basic had an unexpected result") 853 }) 854 } 855 } 856 857 func TestVoteSetMaj23MessageValidateBasic(t *testing.T) { 858 const ( 859 validSignedMsgType types.SignedMsgType = 0x01 860 invalidSignedMsgType types.SignedMsgType = 0x03 861 ) 862 863 validBlockID := types.BlockID{} 864 invalidBlockID := types.BlockID{ 865 Hash: bytes.HexBytes{}, 866 PartsHeader: types.PartSetHeader{ 867 Total: -1, 868 Hash: bytes.HexBytes{}, 869 }, 870 } 871 872 testCases := []struct { // nolint: maligned 873 expectErr bool 874 messageRound int 875 messageHeight int64 876 testName string 877 messageType types.SignedMsgType 878 messageBlockID types.BlockID 879 }{ 880 {false, 0, 0, "Valid Message", validSignedMsgType, validBlockID}, 881 {true, -1, 0, "Invalid Message", validSignedMsgType, validBlockID}, 882 {true, 0, -1, "Invalid Message", validSignedMsgType, validBlockID}, 883 {true, 0, 0, "Invalid Message", invalidSignedMsgType, validBlockID}, 884 {true, 0, 0, "Invalid Message", validSignedMsgType, invalidBlockID}, 885 } 886 887 for _, tc := range testCases { 888 tc := tc 889 t.Run(tc.testName, func(t *testing.T) { 890 message := VoteSetMaj23Message{ 891 Height: tc.messageHeight, 892 Round: tc.messageRound, 893 Type: tc.messageType, 894 BlockID: tc.messageBlockID, 895 } 896 897 assert.Equal(t, tc.expectErr, message.ValidateBasic() != nil, "Validate Basic had an unexpected result") 898 }) 899 } 900 } 901 902 func TestVoteSetBitsMessageValidateBasic(t *testing.T) { 903 testCases := []struct { // nolint: maligned 904 malleateFn func(*VoteSetBitsMessage) 905 expErr string 906 }{ 907 {func(msg *VoteSetBitsMessage) {}, ""}, 908 {func(msg *VoteSetBitsMessage) { msg.Height = -1 }, "negative Height"}, 909 {func(msg *VoteSetBitsMessage) { msg.Round = -1 }, "negative Round"}, 910 {func(msg *VoteSetBitsMessage) { msg.Type = 0x03 }, "invalid Type"}, 911 {func(msg *VoteSetBitsMessage) { 912 msg.BlockID = types.BlockID{ 913 Hash: bytes.HexBytes{}, 914 PartsHeader: types.PartSetHeader{ 915 Total: -1, 916 Hash: bytes.HexBytes{}, 917 }, 918 } 919 }, "wrong BlockID: wrong PartsHeader: negative Total"}, 920 {func(msg *VoteSetBitsMessage) { msg.Votes = bits.NewBitArray(types.MaxVotesCount + 1) }, 921 "votes bit array is too big: 10001, max: 10000"}, 922 } 923 924 for i, tc := range testCases { 925 tc := tc 926 t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) { 927 msg := &VoteSetBitsMessage{ 928 Height: 1, 929 Round: 0, 930 Type: 0x01, 931 Votes: bits.NewBitArray(1), 932 BlockID: types.BlockID{}, 933 } 934 935 tc.malleateFn(msg) 936 err := msg.ValidateBasic() 937 if tc.expErr != "" && assert.Error(t, err) { 938 assert.Contains(t, err.Error(), tc.expErr) 939 } 940 }) 941 } 942 }