github.com/evdatsion/aphelion-dpos-bft@v0.32.1/state/validation_test.go (about)

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