github.com/okex/exchain@v1.8.0/libs/tendermint/blockchain/v0/reactor_test.go (about) 1 package v0 2 3 import ( 4 "os" 5 "sort" 6 "testing" 7 "time" 8 9 "github.com/pkg/errors" 10 "github.com/stretchr/testify/assert" 11 12 dbm "github.com/okex/exchain/libs/tm-db" 13 14 abci "github.com/okex/exchain/libs/tendermint/abci/types" 15 cfg "github.com/okex/exchain/libs/tendermint/config" 16 "github.com/okex/exchain/libs/tendermint/libs/log" 17 "github.com/okex/exchain/libs/tendermint/mock" 18 "github.com/okex/exchain/libs/tendermint/p2p" 19 "github.com/okex/exchain/libs/tendermint/proxy" 20 sm "github.com/okex/exchain/libs/tendermint/state" 21 "github.com/okex/exchain/libs/tendermint/store" 22 "github.com/okex/exchain/libs/tendermint/types" 23 tmtime "github.com/okex/exchain/libs/tendermint/types/time" 24 ) 25 26 var config *cfg.Config 27 28 func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.GenesisDoc, []types.PrivValidator) { 29 validators := make([]types.GenesisValidator, numValidators) 30 privValidators := make([]types.PrivValidator, numValidators) 31 for i := 0; i < numValidators; i++ { 32 val, privVal := types.RandValidator(randPower, minPower) 33 validators[i] = types.GenesisValidator{ 34 PubKey: val.PubKey, 35 Power: val.VotingPower, 36 } 37 privValidators[i] = privVal 38 } 39 sort.Sort(types.PrivValidatorsByAddress(privValidators)) 40 41 return &types.GenesisDoc{ 42 GenesisTime: tmtime.Now(), 43 ChainID: config.ChainID(), 44 Validators: validators, 45 }, privValidators 46 } 47 48 type BlockchainReactorPair struct { 49 reactor *BlockchainReactor 50 app proxy.AppConns 51 } 52 53 func newBlockchainReactor( 54 logger log.Logger, 55 genDoc *types.GenesisDoc, 56 privVals []types.PrivValidator, 57 maxBlockHeight int64) BlockchainReactorPair { 58 if len(privVals) != 1 { 59 panic("only support one validator") 60 } 61 62 app := &testApp{} 63 cc := proxy.NewLocalClientCreator(app) 64 proxyApp := proxy.NewAppConns(cc) 65 err := proxyApp.Start() 66 if err != nil { 67 panic(errors.Wrap(err, "error start app")) 68 } 69 70 blockDB := dbm.NewMemDB() 71 stateDB := dbm.NewMemDB() 72 blockStore := store.NewBlockStore(blockDB) 73 74 state, err := sm.LoadStateFromDBOrGenesisDoc(stateDB, genDoc) 75 if err != nil { 76 panic(errors.Wrap(err, "error constructing state from genesis file")) 77 } 78 79 // Make the BlockchainReactor itself. 80 // NOTE we have to create and commit the blocks first because 81 // pool.height is determined from the store. 82 fastSync := true 83 db := dbm.NewMemDB() 84 blockExec := sm.NewBlockExecutor(db, log.TestingLogger(), proxyApp.Consensus(), 85 mock.Mempool{}, sm.MockEvidencePool{}) 86 sm.SaveState(db, state) 87 88 // let's add some blocks in 89 for blockHeight := int64(1); blockHeight <= maxBlockHeight; blockHeight++ { 90 lastCommit := types.NewCommit(blockHeight-1, 0, types.BlockID{}, nil) 91 if blockHeight > 1 { 92 lastBlockMeta := blockStore.LoadBlockMeta(blockHeight - 1) 93 lastBlock := blockStore.LoadBlock(blockHeight - 1) 94 95 vote, err := types.MakeVote( 96 lastBlock.Header.Height, 97 lastBlockMeta.BlockID, 98 state.Validators, 99 privVals[0], 100 lastBlock.Header.ChainID, 101 time.Now(), 102 ) 103 if err != nil { 104 panic(err) 105 } 106 lastCommit = types.NewCommit(vote.Height, vote.Round, 107 lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()}) 108 } 109 110 thisBlock := makeBlock(blockHeight, state, lastCommit) 111 112 thisParts := thisBlock.MakePartSet(types.BlockPartSizeBytes) 113 blockID := types.BlockID{Hash: thisBlock.Hash(), PartsHeader: thisParts.Header()} 114 115 state, _, err = blockExec.ApplyBlock(state, blockID, thisBlock) 116 if err != nil { 117 panic(errors.Wrap(err, "error apply block")) 118 } 119 120 blockStore.SaveBlock(thisBlock, thisParts, lastCommit) 121 } 122 123 bcReactor := NewBlockchainReactor(state.Copy(), blockExec, blockStore, fastSync) 124 bcReactor.SetLogger(logger.With("module", "blockchain")) 125 126 return BlockchainReactorPair{bcReactor, proxyApp} 127 } 128 129 func TestNoBlockResponse(t *testing.T) { 130 config = cfg.ResetTestRoot("blockchain_reactor_test") 131 defer os.RemoveAll(config.RootDir) 132 genDoc, privVals := randGenesisDoc(1, false, 30) 133 134 maxBlockHeight := int64(65) 135 136 reactorPairs := make([]BlockchainReactorPair, 2) 137 138 reactorPairs[0] = newBlockchainReactor(log.TestingLogger(), genDoc, privVals, maxBlockHeight) 139 reactorPairs[1] = newBlockchainReactor(log.TestingLogger(), genDoc, privVals, 0) 140 141 p2p.MakeConnectedSwitches(config.P2P, 2, func(i int, s *p2p.Switch) *p2p.Switch { 142 s.AddReactor("BLOCKCHAIN", reactorPairs[i].reactor) 143 return s 144 145 }, p2p.Connect2Switches) 146 147 defer func() { 148 for _, r := range reactorPairs { 149 r.reactor.Stop() 150 r.app.Stop() 151 } 152 }() 153 154 tests := []struct { 155 height int64 156 existent bool 157 }{ 158 {maxBlockHeight + 2, false}, 159 {10, true}, 160 {1, true}, 161 {100, false}, 162 } 163 164 for { 165 if reactorPairs[1].reactor.pool.IsCaughtUp() { 166 break 167 } 168 169 time.Sleep(10 * time.Millisecond) 170 } 171 172 assert.Equal(t, maxBlockHeight, reactorPairs[0].reactor.store.Height()) 173 174 for _, tt := range tests { 175 block := reactorPairs[1].reactor.store.LoadBlock(tt.height) 176 if tt.existent { 177 assert.True(t, block != nil) 178 } else { 179 assert.True(t, block == nil) 180 } 181 } 182 } 183 184 func TestBcBlockRequestMessageValidateBasic(t *testing.T) { 185 testCases := []struct { 186 testName string 187 requestHeight int64 188 expectErr bool 189 }{ 190 {"Valid Request Message", 0, false}, 191 {"Valid Request Message", 1, false}, 192 {"Invalid Request Message", -1, true}, 193 } 194 195 for _, tc := range testCases { 196 tc := tc 197 t.Run(tc.testName, func(t *testing.T) { 198 request := bcBlockRequestMessage{Height: tc.requestHeight} 199 assert.Equal(t, tc.expectErr, request.ValidateBasic() != nil, "Validate Basic had an unexpected result") 200 }) 201 } 202 } 203 204 func TestBcNoBlockResponseMessageValidateBasic(t *testing.T) { 205 testCases := []struct { 206 testName string 207 nonResponseHeight int64 208 expectErr bool 209 }{ 210 {"Valid Non-Response Message", 0, false}, 211 {"Valid Non-Response Message", 1, false}, 212 {"Invalid Non-Response Message", -1, true}, 213 } 214 215 for _, tc := range testCases { 216 tc := tc 217 t.Run(tc.testName, func(t *testing.T) { 218 nonResponse := bcNoBlockResponseMessage{Height: tc.nonResponseHeight} 219 assert.Equal(t, tc.expectErr, nonResponse.ValidateBasic() != nil, "Validate Basic had an unexpected result") 220 }) 221 } 222 } 223 224 func TestBcStatusRequestMessageValidateBasic(t *testing.T) { 225 testCases := []struct { 226 testName string 227 requestHeight int64 228 expectErr bool 229 }{ 230 {"Valid Request Message", 0, false}, 231 {"Valid Request Message", 1, false}, 232 {"Invalid Request Message", -1, true}, 233 } 234 235 for _, tc := range testCases { 236 tc := tc 237 t.Run(tc.testName, func(t *testing.T) { 238 request := bcStatusRequestMessage{Height: tc.requestHeight} 239 assert.Equal(t, tc.expectErr, request.ValidateBasic() != nil, "Validate Basic had an unexpected result") 240 }) 241 } 242 } 243 244 func TestBcStatusResponseMessageValidateBasic(t *testing.T) { 245 testCases := []struct { 246 testName string 247 responseHeight int64 248 expectErr bool 249 }{ 250 {"Valid Response Message", 0, false}, 251 {"Valid Response Message", 1, false}, 252 {"Invalid Response Message", -1, true}, 253 } 254 255 for _, tc := range testCases { 256 tc := tc 257 t.Run(tc.testName, func(t *testing.T) { 258 response := bcStatusResponseMessage{Height: tc.responseHeight} 259 assert.Equal(t, tc.expectErr, response.ValidateBasic() != nil, "Validate Basic had an unexpected result") 260 }) 261 } 262 } 263 264 //---------------------------------------------- 265 // utility funcs 266 267 func makeTxs(height int64) (txs []types.Tx) { 268 for i := 0; i < 10; i++ { 269 txs = append(txs, types.Tx([]byte{byte(height), byte(i)})) 270 } 271 return txs 272 } 273 274 func makeBlock(height int64, state sm.State, lastCommit *types.Commit) *types.Block { 275 block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil, state.Validators.GetProposer().Address) 276 return block 277 } 278 279 type testApp struct { 280 abci.BaseApplication 281 } 282 283 var _ abci.Application = (*testApp)(nil) 284 285 func (app *testApp) Info(req abci.RequestInfo) (resInfo abci.ResponseInfo) { 286 return abci.ResponseInfo{} 287 } 288 289 func (app *testApp) BeginBlock(req abci.RequestBeginBlock) abci.ResponseBeginBlock { 290 return abci.ResponseBeginBlock{} 291 } 292 293 func (app *testApp) EndBlock(req abci.RequestEndBlock) abci.ResponseEndBlock { 294 return abci.ResponseEndBlock{} 295 } 296 297 func (app *testApp) DeliverTx(req abci.RequestDeliverTx) abci.ResponseDeliverTx { 298 return abci.ResponseDeliverTx{Events: []abci.Event{}} 299 } 300 301 func (app *testApp) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx { 302 return abci.ResponseCheckTx{} 303 } 304 305 func (app *testApp) Commit(req abci.RequestCommit) abci.ResponseCommit { 306 return abci.ResponseCommit{} 307 } 308 309 func (app *testApp) Query(reqQuery abci.RequestQuery) (resQuery abci.ResponseQuery) { 310 return 311 }