github.com/okex/exchain@v1.8.0/libs/tendermint/state/execution_test.go (about)

     1  package state_test
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  	"github.com/stretchr/testify/require"
     9  
    10  	"github.com/okex/exchain/libs/tendermint/abci/example/kvstore"
    11  	abci "github.com/okex/exchain/libs/tendermint/abci/types"
    12  	"github.com/okex/exchain/libs/tendermint/crypto/ed25519"
    13  	"github.com/okex/exchain/libs/tendermint/crypto/secp256k1"
    14  	"github.com/okex/exchain/libs/tendermint/libs/log"
    15  	"github.com/okex/exchain/libs/tendermint/mock"
    16  	"github.com/okex/exchain/libs/tendermint/proxy"
    17  	sm "github.com/okex/exchain/libs/tendermint/state"
    18  	"github.com/okex/exchain/libs/tendermint/types"
    19  	tmtime "github.com/okex/exchain/libs/tendermint/types/time"
    20  )
    21  
    22  var (
    23  	chainID      = "execution_chain"
    24  	testPartSize = 65536
    25  	nTxsPerBlock = 10
    26  )
    27  
    28  func TestApplyBlock(t *testing.T) {
    29  	app := kvstore.NewApplication()
    30  	app.RetainBlocks = 1
    31  	cc := proxy.NewLocalClientCreator(app)
    32  	proxyApp := proxy.NewAppConns(cc)
    33  	err := proxyApp.Start()
    34  	require.Nil(t, err)
    35  	defer proxyApp.Stop()
    36  
    37  	state, stateDB, _ := makeState(1, 1)
    38  
    39  	blockExec := sm.NewBlockExecutor(stateDB, log.TestingLogger(), proxyApp.Consensus(),
    40  		mock.Mempool{}, sm.MockEvidencePool{})
    41  
    42  	block := makeBlock(state, 1)
    43  	blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()}
    44  
    45  	_, retainHeight, err := blockExec.ApplyBlock(state, blockID, block)
    46  	require.Nil(t, err)
    47  	assert.EqualValues(t, retainHeight, 1)
    48  
    49  	// TODO check state and mempool
    50  }
    51  
    52  // TestBeginBlockValidators ensures we send absent validators list.
    53  func TestBeginBlockValidators(t *testing.T) {
    54  	app := &testApp{}
    55  	cc := proxy.NewLocalClientCreator(app)
    56  	proxyApp := proxy.NewAppConns(cc)
    57  	err := proxyApp.Start()
    58  	require.Nil(t, err)
    59  	defer proxyApp.Stop()
    60  
    61  	state, stateDB, _ := makeState(2, 2)
    62  
    63  	prevHash := state.LastBlockID.Hash
    64  	prevParts := types.PartSetHeader{}
    65  	prevBlockID := types.BlockID{Hash: prevHash, PartsHeader: prevParts}
    66  
    67  	var (
    68  		now        = tmtime.Now()
    69  		commitSig0 = types.NewCommitSigForBlock(
    70  			[]byte("Signature1"),
    71  			state.Validators.Validators[0].Address,
    72  			now)
    73  		commitSig1 = types.NewCommitSigForBlock(
    74  			[]byte("Signature2"),
    75  			state.Validators.Validators[1].Address,
    76  			now)
    77  		absentSig = types.NewCommitSigAbsent()
    78  	)
    79  
    80  	testCases := []struct {
    81  		desc                     string
    82  		lastCommitSigs           []types.CommitSig
    83  		expectedAbsentValidators []int
    84  	}{
    85  		{"none absent", []types.CommitSig{commitSig0, commitSig1}, []int{}},
    86  		{"one absent", []types.CommitSig{commitSig0, absentSig}, []int{1}},
    87  		{"multiple absent", []types.CommitSig{absentSig, absentSig}, []int{0, 1}},
    88  	}
    89  
    90  	for _, tc := range testCases {
    91  		lastCommit := types.NewCommit(1, 0, prevBlockID, tc.lastCommitSigs)
    92  
    93  		// block for height 2
    94  		block, _ := state.MakeBlock(2, makeTxs(2), lastCommit, nil, state.Validators.GetProposer().Address)
    95  
    96  		_, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), stateDB)
    97  		require.Nil(t, err, tc.desc)
    98  
    99  		// -> app receives a list of validators with a bool indicating if they signed
   100  		ctr := 0
   101  		for i, v := range app.CommitVotes {
   102  			if ctr < len(tc.expectedAbsentValidators) &&
   103  				tc.expectedAbsentValidators[ctr] == i {
   104  
   105  				assert.False(t, v.SignedLastBlock)
   106  				ctr++
   107  			} else {
   108  				assert.True(t, v.SignedLastBlock)
   109  			}
   110  		}
   111  	}
   112  }
   113  
   114  // TestBeginBlockByzantineValidators ensures we send byzantine validators list.
   115  func TestBeginBlockByzantineValidators(t *testing.T) {
   116  	app := &testApp{}
   117  	cc := proxy.NewLocalClientCreator(app)
   118  	proxyApp := proxy.NewAppConns(cc)
   119  	err := proxyApp.Start()
   120  	require.Nil(t, err)
   121  	defer proxyApp.Stop()
   122  
   123  	state, stateDB, _ := makeState(2, 12)
   124  
   125  	prevHash := state.LastBlockID.Hash
   126  	prevParts := types.PartSetHeader{}
   127  	prevBlockID := types.BlockID{Hash: prevHash, PartsHeader: prevParts}
   128  
   129  	height1, idx1, val1 := int64(8), 0, state.Validators.Validators[0].Address
   130  	height2, idx2, val2 := int64(3), 1, state.Validators.Validators[1].Address
   131  	ev1 := types.NewMockEvidence(height1, time.Now(), idx1, val1)
   132  	ev2 := types.NewMockEvidence(height2, time.Now(), idx2, val2)
   133  
   134  	now := tmtime.Now()
   135  	valSet := state.Validators
   136  	testCases := []struct {
   137  		desc                        string
   138  		evidence                    []types.Evidence
   139  		expectedByzantineValidators []abci.Evidence
   140  	}{
   141  		{"none byzantine", []types.Evidence{}, []abci.Evidence{}},
   142  		{"one byzantine", []types.Evidence{ev1}, []abci.Evidence{types.TM2PB.Evidence(ev1, valSet, now)}},
   143  		{"multiple byzantine", []types.Evidence{ev1, ev2}, []abci.Evidence{
   144  			types.TM2PB.Evidence(ev1, valSet, now),
   145  			types.TM2PB.Evidence(ev2, valSet, now)}},
   146  	}
   147  
   148  	var (
   149  		commitSig0 = types.NewCommitSigForBlock(
   150  			[]byte("Signature1"),
   151  			state.Validators.Validators[0].Address,
   152  			now)
   153  		commitSig1 = types.NewCommitSigForBlock(
   154  			[]byte("Signature2"),
   155  			state.Validators.Validators[1].Address,
   156  			now)
   157  	)
   158  	commitSigs := []types.CommitSig{commitSig0, commitSig1}
   159  	lastCommit := types.NewCommit(9, 0, prevBlockID, commitSigs)
   160  	for _, tc := range testCases {
   161  
   162  		block, _ := state.MakeBlock(10, makeTxs(2), lastCommit, nil, state.Validators.GetProposer().Address)
   163  		block.Time = now
   164  		block.Evidence.Evidence = tc.evidence
   165  		_, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), stateDB)
   166  		require.Nil(t, err, tc.desc)
   167  
   168  		// -> app must receive an index of the byzantine validator
   169  		assert.Equal(t, tc.expectedByzantineValidators, app.ByzantineValidators, tc.desc)
   170  	}
   171  }
   172  
   173  func TestValidateValidatorUpdates(t *testing.T) {
   174  	pubkey1 := ed25519.GenPrivKey().PubKey()
   175  	pubkey2 := ed25519.GenPrivKey().PubKey()
   176  
   177  	secpKey := secp256k1.GenPrivKey().PubKey()
   178  
   179  	defaultValidatorParams := types.ValidatorParams{PubKeyTypes: []string{types.ABCIPubKeyTypeEd25519}}
   180  
   181  	testCases := []struct {
   182  		name string
   183  
   184  		abciUpdates     []abci.ValidatorUpdate
   185  		validatorParams types.ValidatorParams
   186  
   187  		shouldErr bool
   188  	}{
   189  		{
   190  			"adding a validator is OK",
   191  
   192  			[]abci.ValidatorUpdate{{PubKey: types.TM2PB.PubKey(pubkey2), Power: 20}},
   193  			defaultValidatorParams,
   194  
   195  			false,
   196  		},
   197  		{
   198  			"updating a validator is OK",
   199  
   200  			[]abci.ValidatorUpdate{{PubKey: types.TM2PB.PubKey(pubkey1), Power: 20}},
   201  			defaultValidatorParams,
   202  
   203  			false,
   204  		},
   205  		{
   206  			"removing a validator is OK",
   207  
   208  			[]abci.ValidatorUpdate{{PubKey: types.TM2PB.PubKey(pubkey2), Power: 0}},
   209  			defaultValidatorParams,
   210  
   211  			false,
   212  		},
   213  		{
   214  			"adding a validator with negative power results in error",
   215  
   216  			[]abci.ValidatorUpdate{{PubKey: types.TM2PB.PubKey(pubkey2), Power: -100}},
   217  			defaultValidatorParams,
   218  
   219  			true,
   220  		},
   221  		{
   222  			"adding a validator with pubkey thats not in validator params results in error",
   223  
   224  			[]abci.ValidatorUpdate{{PubKey: types.TM2PB.PubKey(secpKey), Power: -100}},
   225  			defaultValidatorParams,
   226  
   227  			true,
   228  		},
   229  	}
   230  
   231  	for _, tc := range testCases {
   232  		tc := tc
   233  		t.Run(tc.name, func(t *testing.T) {
   234  			err := sm.ValidateValidatorUpdates(tc.abciUpdates, tc.validatorParams)
   235  			if tc.shouldErr {
   236  				assert.Error(t, err)
   237  			} else {
   238  				assert.NoError(t, err)
   239  			}
   240  		})
   241  	}
   242  }
   243  
   244  func TestUpdateValidators(t *testing.T) {
   245  	pubkey1 := ed25519.GenPrivKey().PubKey()
   246  	val1 := types.NewValidator(pubkey1, 10)
   247  	pubkey2 := ed25519.GenPrivKey().PubKey()
   248  	val2 := types.NewValidator(pubkey2, 20)
   249  
   250  	testCases := []struct {
   251  		name string
   252  
   253  		currentSet  *types.ValidatorSet
   254  		abciUpdates []abci.ValidatorUpdate
   255  
   256  		resultingSet *types.ValidatorSet
   257  		shouldErr    bool
   258  	}{
   259  		{
   260  			"adding a validator is OK",
   261  
   262  			types.NewValidatorSet([]*types.Validator{val1}),
   263  			[]abci.ValidatorUpdate{{PubKey: types.TM2PB.PubKey(pubkey2), Power: 20}},
   264  
   265  			types.NewValidatorSet([]*types.Validator{val1, val2}),
   266  			false,
   267  		},
   268  		{
   269  			"updating a validator is OK",
   270  
   271  			types.NewValidatorSet([]*types.Validator{val1}),
   272  			[]abci.ValidatorUpdate{{PubKey: types.TM2PB.PubKey(pubkey1), Power: 20}},
   273  
   274  			types.NewValidatorSet([]*types.Validator{types.NewValidator(pubkey1, 20)}),
   275  			false,
   276  		},
   277  		{
   278  			"removing a validator is OK",
   279  
   280  			types.NewValidatorSet([]*types.Validator{val1, val2}),
   281  			[]abci.ValidatorUpdate{{PubKey: types.TM2PB.PubKey(pubkey2), Power: 0}},
   282  
   283  			types.NewValidatorSet([]*types.Validator{val1}),
   284  			false,
   285  		},
   286  		{
   287  			"removing a non-existing validator results in error",
   288  
   289  			types.NewValidatorSet([]*types.Validator{val1}),
   290  			[]abci.ValidatorUpdate{{PubKey: types.TM2PB.PubKey(pubkey2), Power: 0}},
   291  
   292  			types.NewValidatorSet([]*types.Validator{val1}),
   293  			true,
   294  		},
   295  	}
   296  
   297  	for _, tc := range testCases {
   298  		tc := tc
   299  		t.Run(tc.name, func(t *testing.T) {
   300  			updates, err := types.PB2TM.ValidatorUpdates(tc.abciUpdates)
   301  			assert.NoError(t, err)
   302  			err = tc.currentSet.UpdateWithChangeSet(updates)
   303  			if tc.shouldErr {
   304  				assert.Error(t, err)
   305  			} else {
   306  				assert.NoError(t, err)
   307  				require.Equal(t, tc.resultingSet.Size(), tc.currentSet.Size())
   308  
   309  				assert.Equal(t, tc.resultingSet.TotalVotingPower(), tc.currentSet.TotalVotingPower())
   310  
   311  				assert.Equal(t, tc.resultingSet.Validators[0].Address, tc.currentSet.Validators[0].Address)
   312  				if tc.resultingSet.Size() > 1 {
   313  					assert.Equal(t, tc.resultingSet.Validators[1].Address, tc.currentSet.Validators[1].Address)
   314  				}
   315  			}
   316  		})
   317  	}
   318  }
   319  
   320  // TestEndBlockValidatorUpdates ensures we update validator set and send an event.
   321  /*
   322  func TestEndBlockValidatorUpdates(t *testing.T) {
   323  	app := &testApp{}
   324  	cc := proxy.NewLocalClientCreator(app)
   325  	proxyApp := proxy.NewAppConns(cc)
   326  	err := proxyApp.Start()
   327  	require.Nil(t, err)
   328  	defer proxyApp.Stop()
   329  
   330  	state, stateDB, _ := makeState(1, 1)
   331  
   332  	blockExec := sm.NewBlockExecutor(
   333  		stateDB,
   334  		log.TestingLogger(),
   335  		proxyApp.Consensus(),
   336  		mock.Mempool{},
   337  		sm.MockEvidencePool{},
   338  	)
   339  
   340  	eventBus := types.NewEventBus()
   341  	err = eventBus.Start()
   342  	require.NoError(t, err)
   343  	defer eventBus.Stop()
   344  	blockExec.SetEventBus(eventBus)
   345  
   346  	updatesSub, err := eventBus.Subscribe(
   347  		context.Background(),
   348  		"TestEndBlockValidatorUpdates",
   349  		types.EventQueryValidatorSetUpdates,
   350  	)
   351  	require.NoError(t, err)
   352  
   353  	block := makeBlock(state, 1)
   354  	blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()}
   355  
   356  	pubkey := ed25519.GenPrivKey().PubKey()
   357  	app.ValidatorUpdates = []abci.ValidatorUpdate{
   358  		{PubKey: types.TM2PB.PubKey(pubkey), Power: 10},
   359  	}
   360  
   361  	state, _, err = blockExec.ApplyBlock(state, blockID, block)
   362  	require.Nil(t, err)
   363  
   364  	// test new validator was added to NextValidators
   365  	if assert.Equal(t, state.Validators.Size()+1, state.NextValidators.Size()) {
   366  		idx, _ := state.NextValidators.GetByAddress(pubkey.Address())
   367  		if idx < 0 {
   368  			t.Fatalf("can't find address %v in the set %v", pubkey.Address(), state.NextValidators)
   369  		}
   370  	}
   371  
   372  	// test we threw an event
   373  	select {
   374  	case msg := <-updatesSub.Out():
   375  		event, ok := msg.Data().(types.EventDataValidatorSetUpdates)
   376  		require.True(t, ok, "Expected event of type EventDataValidatorSetUpdates, got %T", msg.Data())
   377  		if assert.NotEmpty(t, event.ValidatorUpdates) {
   378  			assert.Equal(t, pubkey, event.ValidatorUpdates[0].PubKey)
   379  			assert.EqualValues(t, 10, event.ValidatorUpdates[0].VotingPower)
   380  		}
   381  	case <-updatesSub.Cancelled():
   382  		t.Fatalf("updatesSub was cancelled (reason: %v)", updatesSub.Err())
   383  	case <-time.After(1 * time.Second):
   384  		t.Fatal("Did not receive EventValidatorSetUpdates within 1 sec.")
   385  	}
   386  }
   387  */
   388  
   389  // TestEndBlockValidatorUpdatesResultingInEmptySet checks that processing validator updates that
   390  // would result in empty set causes no panic, an error is raised and NextValidators is not updated
   391  func TestEndBlockValidatorUpdatesResultingInEmptySet(t *testing.T) {
   392  	app := &testApp{}
   393  	cc := proxy.NewLocalClientCreator(app)
   394  	proxyApp := proxy.NewAppConns(cc)
   395  	err := proxyApp.Start()
   396  	require.Nil(t, err)
   397  	defer proxyApp.Stop()
   398  
   399  	state, stateDB, _ := makeState(1, 1)
   400  	blockExec := sm.NewBlockExecutor(
   401  		stateDB,
   402  		log.TestingLogger(),
   403  		proxyApp.Consensus(),
   404  		mock.Mempool{},
   405  		sm.MockEvidencePool{},
   406  	)
   407  
   408  	block := makeBlock(state, 1)
   409  	blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()}
   410  
   411  	// Remove the only validator
   412  	app.ValidatorUpdates = []abci.ValidatorUpdate{
   413  		{PubKey: types.TM2PB.PubKey(state.Validators.Validators[0].PubKey), Power: 0},
   414  	}
   415  
   416  	assert.NotPanics(t, func() { state, _, err = blockExec.ApplyBlock(state, blockID, block) })
   417  	assert.NotNil(t, err)
   418  	assert.NotEmpty(t, state.NextValidators.Validators)
   419  
   420  }