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 }