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  }