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

     1  package state_test
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"github.com/stretchr/testify/require"
     8  
     9  	"github.com/okex/exchain/libs/tendermint/crypto/ed25519"
    10  	"github.com/okex/exchain/libs/tendermint/crypto/tmhash"
    11  	"github.com/okex/exchain/libs/tendermint/libs/log"
    12  	"github.com/okex/exchain/libs/tendermint/mock"
    13  	sm "github.com/okex/exchain/libs/tendermint/state"
    14  	"github.com/okex/exchain/libs/tendermint/types"
    15  	tmtime "github.com/okex/exchain/libs/tendermint/types/time"
    16  )
    17  
    18  const validationTestsStopHeight int64 = 10
    19  
    20  func TestValidateBlockHeader(t *testing.T) {
    21  	proxyApp := newTestApp()
    22  	require.NoError(t, proxyApp.Start())
    23  	defer proxyApp.Stop()
    24  
    25  	state, stateDB, privVals := makeState(3, 1)
    26  	blockExec := sm.NewBlockExecutor(
    27  		stateDB,
    28  		log.TestingLogger(),
    29  		proxyApp.Consensus(),
    30  		mock.Mempool{},
    31  		sm.MockEvidencePool{},
    32  	)
    33  	lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil)
    34  
    35  	// some bad values
    36  	wrongHash := tmhash.Sum([]byte("this hash is wrong"))
    37  	wrongVersion1 := state.Version.Consensus
    38  	wrongVersion1.Block++
    39  	wrongVersion2 := state.Version.Consensus
    40  	wrongVersion2.App++
    41  
    42  	// Manipulation of any header field causes failure.
    43  	testCases := []struct {
    44  		name          string
    45  		malleateBlock func(block *types.Block)
    46  	}{
    47  		{"Version wrong1", func(block *types.Block) { block.Version = wrongVersion1 }},
    48  		{"Version wrong2", func(block *types.Block) { block.Version = wrongVersion2 }},
    49  		{"ChainID wrong", func(block *types.Block) { block.ChainID = "not-the-real-one" }},
    50  		{"Height wrong", func(block *types.Block) { block.Height += 10 }},
    51  		{"Time wrong", func(block *types.Block) { block.Time = block.Time.Add(-time.Second * 1) }},
    52  
    53  		{"LastBlockID wrong", func(block *types.Block) { block.LastBlockID.PartsHeader.Total += 10 }},
    54  		{"LastCommitHash wrong", func(block *types.Block) { block.LastCommitHash = wrongHash }},
    55  		{"DataHash wrong", func(block *types.Block) { block.DataHash = wrongHash }},
    56  
    57  		{"ValidatorsHash wrong", func(block *types.Block) { block.ValidatorsHash = wrongHash }},
    58  		{"NextValidatorsHash wrong", func(block *types.Block) { block.NextValidatorsHash = wrongHash }},
    59  		{"ConsensusHash wrong", func(block *types.Block) { block.ConsensusHash = wrongHash }},
    60  		{"AppHash wrong", func(block *types.Block) { block.AppHash = wrongHash }},
    61  		{"LastResultsHash wrong", func(block *types.Block) { block.LastResultsHash = wrongHash }},
    62  
    63  		{"EvidenceHash wrong", func(block *types.Block) { block.EvidenceHash = wrongHash }},
    64  		{"Proposer wrong", func(block *types.Block) { block.ProposerAddress = ed25519.GenPrivKey().PubKey().Address() }},
    65  		{"Proposer invalid", func(block *types.Block) { block.ProposerAddress = []byte("wrong size") }},
    66  	}
    67  
    68  	// Build up state for multiple heights
    69  	for height := int64(1); height < validationTestsStopHeight; height++ {
    70  		proposerAddr := state.Validators.GetProposer().Address
    71  		/*
    72  			Invalid blocks don't pass
    73  		*/
    74  		for _, tc := range testCases {
    75  			block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil, proposerAddr)
    76  			tc.malleateBlock(block)
    77  			err := blockExec.ValidateBlock(state, block)
    78  			require.Error(t, err, tc.name)
    79  		}
    80  
    81  		/*
    82  			A good block passes
    83  		*/
    84  		var err error
    85  		state, _, lastCommit, err = makeAndCommitGoodBlock(state, height, lastCommit, proposerAddr, blockExec, privVals, nil)
    86  		require.NoError(t, err, "height %d", height)
    87  	}
    88  }
    89  
    90  func TestValidateBlockCommit(t *testing.T) {
    91  	proxyApp := newTestApp()
    92  	require.NoError(t, proxyApp.Start())
    93  	defer proxyApp.Stop()
    94  
    95  	state, stateDB, privVals := makeState(1, 1)
    96  	blockExec := sm.NewBlockExecutor(
    97  		stateDB,
    98  		log.TestingLogger(),
    99  		proxyApp.Consensus(),
   100  		mock.Mempool{},
   101  		sm.MockEvidencePool{},
   102  	)
   103  	lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil)
   104  	wrongSigsCommit := types.NewCommit(1, 0, types.BlockID{}, nil)
   105  	badPrivVal := types.NewMockPV()
   106  
   107  	for height := int64(1); height < validationTestsStopHeight; height++ {
   108  		proposerAddr := state.Validators.GetProposer().Address
   109  		if height > 1 {
   110  			/*
   111  				#2589: ensure state.LastValidators.VerifyCommit fails here
   112  			*/
   113  			// should be height-1 instead of height
   114  			wrongHeightVote, err := types.MakeVote(
   115  				height,
   116  				state.LastBlockID,
   117  				state.Validators,
   118  				privVals[proposerAddr.String()],
   119  				chainID,
   120  				time.Now(),
   121  			)
   122  			require.NoError(t, err, "height %d", height)
   123  			wrongHeightCommit := types.NewCommit(
   124  				wrongHeightVote.Height,
   125  				wrongHeightVote.Round,
   126  				state.LastBlockID,
   127  				[]types.CommitSig{wrongHeightVote.CommitSig()},
   128  			)
   129  			block, _ := state.MakeBlock(height, makeTxs(height), wrongHeightCommit, nil, proposerAddr)
   130  			err = blockExec.ValidateBlock(state, block)
   131  			_, isErrInvalidCommitHeight := err.(types.ErrInvalidCommitHeight)
   132  			require.True(t, isErrInvalidCommitHeight, "expected ErrInvalidCommitHeight at height %d but got: %v", height, err)
   133  
   134  			/*
   135  				#2589: test len(block.LastCommit.Signatures) == state.LastValidators.Size()
   136  			*/
   137  			block, _ = state.MakeBlock(height, makeTxs(height), wrongSigsCommit, nil, proposerAddr)
   138  			err = blockExec.ValidateBlock(state, block)
   139  			_, isErrInvalidCommitSignatures := err.(types.ErrInvalidCommitSignatures)
   140  			require.True(t, isErrInvalidCommitSignatures,
   141  				"expected ErrInvalidCommitSignatures at height %d, but got: %v",
   142  				height,
   143  				err,
   144  			)
   145  		}
   146  
   147  		/*
   148  			A good block passes
   149  		*/
   150  		var err error
   151  		var blockID types.BlockID
   152  		state, blockID, lastCommit, err = makeAndCommitGoodBlock(
   153  			state,
   154  			height,
   155  			lastCommit,
   156  			proposerAddr,
   157  			blockExec,
   158  			privVals,
   159  			nil,
   160  		)
   161  		require.NoError(t, err, "height %d", height)
   162  
   163  		/*
   164  			wrongSigsCommit is fine except for the extra bad precommit
   165  		*/
   166  		goodVote, err := types.MakeVote(height,
   167  			blockID,
   168  			state.Validators,
   169  			privVals[proposerAddr.String()],
   170  			chainID,
   171  			time.Now(),
   172  		)
   173  		require.NoError(t, err, "height %d", height)
   174  
   175  		bpvPubKey, err := badPrivVal.GetPubKey()
   176  		require.NoError(t, err)
   177  
   178  		badVote := &types.Vote{
   179  			ValidatorAddress: bpvPubKey.Address(),
   180  			ValidatorIndex:   0,
   181  			Height:           height,
   182  			Round:            0,
   183  			Timestamp:        tmtime.Now(),
   184  			Type:             types.PrecommitType,
   185  			BlockID:          blockID,
   186  		}
   187  		err = badPrivVal.SignVote(chainID, goodVote)
   188  		require.NoError(t, err, "height %d", height)
   189  		err = badPrivVal.SignVote(chainID, badVote)
   190  		require.NoError(t, err, "height %d", height)
   191  
   192  		wrongSigsCommit = types.NewCommit(goodVote.Height, goodVote.Round,
   193  			blockID, []types.CommitSig{goodVote.CommitSig(), badVote.CommitSig()})
   194  	}
   195  }
   196  
   197  func TestValidateBlockEvidence(t *testing.T) {
   198  	proxyApp := newTestApp()
   199  	require.NoError(t, proxyApp.Start())
   200  	defer proxyApp.Stop()
   201  
   202  	state, stateDB, privVals := makeState(3, 1)
   203  	blockExec := sm.NewBlockExecutor(
   204  		stateDB,
   205  		log.TestingLogger(),
   206  		proxyApp.Consensus(),
   207  		mock.Mempool{},
   208  		sm.MockEvidencePool{},
   209  	)
   210  	lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil)
   211  
   212  	for height := int64(1); height < validationTestsStopHeight; height++ {
   213  		proposerAddr := state.Validators.GetProposer().Address
   214  		proposerIdx, _ := state.Validators.GetByAddress(proposerAddr)
   215  		goodEvidence := types.NewMockEvidence(height, time.Now(), proposerIdx, proposerAddr)
   216  		if height > 1 {
   217  			/*
   218  				A block with too much evidence fails
   219  			*/
   220  			maxBlockSize := state.ConsensusParams.Block.MaxBytes
   221  			maxNumEvidence, _ := types.MaxEvidencePerBlock(maxBlockSize)
   222  			require.True(t, maxNumEvidence > 2)
   223  			evidence := make([]types.Evidence, 0)
   224  			// one more than the maximum allowed evidence
   225  			for i := int64(0); i <= maxNumEvidence; i++ {
   226  				evidence = append(evidence, goodEvidence)
   227  			}
   228  			block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, evidence, proposerAddr)
   229  			err := blockExec.ValidateBlock(state, block)
   230  			_, ok := err.(*types.ErrEvidenceOverflow)
   231  			require.True(t, ok, "expected error to be of type ErrEvidenceOverflow at height %d", height)
   232  		}
   233  
   234  		/*
   235  			A good block with several pieces of good evidence passes
   236  		*/
   237  		maxBlockSize := state.ConsensusParams.Block.MaxBytes
   238  		maxNumEvidence, _ := types.MaxEvidencePerBlock(maxBlockSize)
   239  		require.True(t, maxNumEvidence > 2)
   240  		evidence := make([]types.Evidence, 0)
   241  		// precisely the amount of allowed evidence
   242  		for i := int64(0); i < maxNumEvidence; i++ {
   243  			evidence = append(evidence, goodEvidence)
   244  		}
   245  
   246  		var err error
   247  		state, _, lastCommit, err = makeAndCommitGoodBlock(
   248  			state,
   249  			height,
   250  			lastCommit,
   251  			proposerAddr,
   252  			blockExec,
   253  			privVals,
   254  			evidence,
   255  		)
   256  		require.NoError(t, err, "height %d", height)
   257  	}
   258  }
   259  
   260  func TestValidateFailBlockOnCommittedEvidence(t *testing.T) {
   261  	var height int64 = 1
   262  	state, stateDB, _ := makeState(1, int(height))
   263  
   264  	blockExec := sm.NewBlockExecutor(stateDB, log.TestingLogger(), nil, nil, mockEvPoolAlwaysCommitted{})
   265  	// A block with a couple pieces of evidence passes.
   266  	block := makeBlock(state, height)
   267  	addr, _ := state.Validators.GetByIndex(0)
   268  	alreadyCommittedEvidence := types.NewMockEvidence(height, time.Now(), 0, addr)
   269  	block.Evidence.Evidence = []types.Evidence{alreadyCommittedEvidence}
   270  	block.EvidenceHash = block.Evidence.Hash()
   271  	err := blockExec.ValidateBlock(state, block)
   272  
   273  	require.Error(t, err)
   274  	require.IsType(t, err, &types.ErrEvidenceInvalid{})
   275  }