github.com/adoriasoft/tendermint@v0.34.0-dev1.0.20200722151356-96d84601a75a/evidence/reactor_test.go (about) 1 package evidence 2 3 import ( 4 "fmt" 5 "sync" 6 "testing" 7 "time" 8 9 "github.com/go-kit/kit/log/term" 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 13 dbm "github.com/tendermint/tm-db" 14 15 cfg "github.com/tendermint/tendermint/config" 16 "github.com/tendermint/tendermint/libs/log" 17 "github.com/tendermint/tendermint/p2p" 18 sm "github.com/tendermint/tendermint/state" 19 "github.com/tendermint/tendermint/types" 20 ) 21 22 // evidenceLogger is a TestingLogger which uses a different 23 // color for each validator ("validator" key must exist). 24 func evidenceLogger() log.Logger { 25 return log.TestingLoggerWithColorFn(func(keyvals ...interface{}) term.FgBgColor { 26 for i := 0; i < len(keyvals)-1; i += 2 { 27 if keyvals[i] == "validator" { 28 return term.FgBgColor{Fg: term.Color(uint8(keyvals[i+1].(int) + 1))} 29 } 30 } 31 return term.FgBgColor{} 32 }) 33 } 34 35 // connect N evidence reactors through N switches 36 func makeAndConnectReactors(config *cfg.Config, stateDBs []dbm.DB) []*Reactor { 37 N := len(stateDBs) 38 39 reactors := make([]*Reactor, N) 40 logger := evidenceLogger() 41 42 for i := 0; i < N; i++ { 43 evidenceDB := dbm.NewMemDB() 44 blockStoreDB := dbm.NewMemDB() 45 blockStore := initializeBlockStore(blockStoreDB, sm.LoadState(stateDBs[i]), []byte("myval")) 46 pool, err := NewPool(stateDBs[i], evidenceDB, blockStore) 47 if err != nil { 48 panic(err) 49 } 50 reactors[i] = NewReactor(pool) 51 reactors[i].SetLogger(logger.With("validator", i)) 52 } 53 54 p2p.MakeConnectedSwitches(config.P2P, N, func(i int, s *p2p.Switch) *p2p.Switch { 55 s.AddReactor("EVIDENCE", reactors[i]) 56 return s 57 58 }, p2p.Connect2Switches) 59 60 return reactors 61 } 62 63 // wait for all evidence on all reactors 64 func waitForEvidence(t *testing.T, evs types.EvidenceList, reactors []*Reactor) { 65 // wait for the evidence in all evpools 66 wg := new(sync.WaitGroup) 67 for i := 0; i < len(reactors); i++ { 68 wg.Add(1) 69 go _waitForEvidence(t, wg, evs, i, reactors) 70 } 71 72 done := make(chan struct{}) 73 go func() { 74 wg.Wait() 75 close(done) 76 }() 77 78 timer := time.After(timeout) 79 select { 80 case <-timer: 81 t.Fatal("Timed out waiting for evidence") 82 case <-done: 83 } 84 } 85 86 // wait for all evidence on a single evpool 87 func _waitForEvidence( 88 t *testing.T, 89 wg *sync.WaitGroup, 90 evs types.EvidenceList, 91 reactorIdx int, 92 reactors []*Reactor, 93 ) { 94 evpool := reactors[reactorIdx].evpool 95 for len(evpool.AllPendingEvidence()) != len(evs) { 96 time.Sleep(time.Millisecond * 100) 97 } 98 99 reapedEv := evpool.AllPendingEvidence() 100 // put the reaped evidence in a map so we can quickly check we got everything 101 evMap := make(map[string]types.Evidence) 102 for _, e := range reapedEv { 103 evMap[string(e.Hash())] = e 104 } 105 for i, expectedEv := range evs { 106 gotEv := evMap[string(expectedEv.Hash())] 107 assert.Equal(t, expectedEv, gotEv, 108 fmt.Sprintf("evidence at index %d on reactor %d don't match: %v vs %v", 109 i, reactorIdx, expectedEv, gotEv)) 110 } 111 112 wg.Done() 113 } 114 115 func sendEvidence(t *testing.T, evpool *Pool, val types.PrivValidator, n int) types.EvidenceList { 116 evList := make([]types.Evidence, n) 117 for i := 0; i < n; i++ { 118 ev := types.NewMockDuplicateVoteEvidenceWithValidator(int64(i+1), time.Now().UTC(), val, evidenceChainID) 119 err := evpool.AddEvidence(ev) 120 require.NoError(t, err) 121 evList[i] = ev 122 } 123 return evList 124 } 125 126 var ( 127 numEvidence = 10 128 timeout = 120 * time.Second // ridiculously high because CircleCI is slow 129 ) 130 131 func TestReactorBroadcastEvidence(t *testing.T) { 132 config := cfg.TestConfig() 133 N := 7 134 135 // create statedb for everyone 136 stateDBs := make([]dbm.DB, N) 137 val := types.NewMockPV() 138 // we need validators saved for heights at least as high as we have evidence for 139 height := int64(numEvidence) + 10 140 for i := 0; i < N; i++ { 141 stateDBs[i] = initializeValidatorState(val, height) 142 } 143 144 // make reactors from statedb 145 reactors := makeAndConnectReactors(config, stateDBs) 146 147 // set the peer height on each reactor 148 for _, r := range reactors { 149 for _, peer := range r.Switch.Peers().List() { 150 ps := peerState{height} 151 peer.Set(types.PeerStateKey, ps) 152 } 153 } 154 155 // send a bunch of valid evidence to the first reactor's evpool 156 // and wait for them all to be received in the others 157 evList := sendEvidence(t, reactors[0].evpool, val, numEvidence) 158 waitForEvidence(t, evList, reactors) 159 } 160 161 type peerState struct { 162 height int64 163 } 164 165 func (ps peerState) GetHeight() int64 { 166 return ps.height 167 } 168 169 func TestReactorSelectiveBroadcast(t *testing.T) { 170 config := cfg.TestConfig() 171 172 val := types.NewMockPV() 173 height1 := int64(numEvidence) + 10 174 height2 := int64(numEvidence) / 2 175 176 // DB1 is ahead of DB2 177 stateDB1 := initializeValidatorState(val, height1) 178 stateDB2 := initializeValidatorState(val, height2) 179 180 // make reactors from statedb 181 reactors := makeAndConnectReactors(config, []dbm.DB{stateDB1, stateDB2}) 182 183 // set the peer height on each reactor 184 for _, r := range reactors { 185 for _, peer := range r.Switch.Peers().List() { 186 ps := peerState{height1} 187 peer.Set(types.PeerStateKey, ps) 188 } 189 } 190 191 // update the first reactor peer's height to be very small 192 peer := reactors[0].Switch.Peers().List()[0] 193 ps := peerState{height2} 194 peer.Set(types.PeerStateKey, ps) 195 196 // send a bunch of valid evidence to the first reactor's evpool 197 evList := sendEvidence(t, reactors[0].evpool, val, numEvidence) 198 199 // only ones less than the peers height should make it through 200 waitForEvidence(t, evList[:numEvidence/2], reactors[1:2]) 201 202 // peers should still be connected 203 peers := reactors[1].Switch.Peers().List() 204 assert.Equal(t, 1, len(peers)) 205 }