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 }