github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/bft/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/gnolang/gno/tm2/pkg/bft/mempool/mock" 10 sm "github.com/gnolang/gno/tm2/pkg/bft/state" 11 "github.com/gnolang/gno/tm2/pkg/bft/types" 12 tmtime "github.com/gnolang/gno/tm2/pkg/bft/types/time" 13 "github.com/gnolang/gno/tm2/pkg/crypto" 14 "github.com/gnolang/gno/tm2/pkg/crypto/ed25519" 15 "github.com/gnolang/gno/tm2/pkg/crypto/tmhash" 16 "github.com/gnolang/gno/tm2/pkg/log" 17 ) 18 19 const validationTestsStopHeight int64 = 10 20 21 func TestValidateBlockHeader(t *testing.T) { 22 t.Parallel() 23 24 proxyApp := newTestApp() 25 require.NoError(t, proxyApp.Start()) 26 defer proxyApp.Stop() 27 28 state, stateDB, privVals := makeState(3, 1) 29 blockExec := sm.NewBlockExecutor(stateDB, log.NewTestingLogger(t), proxyApp.Consensus(), mock.Mempool{}) 30 lastCommit := types.NewCommit(types.BlockID{}, nil) 31 32 // some bad values 33 wrongHash := tmhash.Sum([]byte("this hash is wrong")) 34 35 // Manipulation of any header field causes failure. 36 testCases := []struct { 37 name string 38 malleateBlock func(block *types.Block) 39 }{ 40 {"BlockVersion wrong", func(block *types.Block) { block.Version += "-wrong" }}, 41 {"AppVersion wrong", func(block *types.Block) { block.AppVersion += "-wrong" }}, 42 {"ChainID wrong", func(block *types.Block) { block.ChainID = "not-the-real-one" }}, 43 {"Height wrong", func(block *types.Block) { block.Height += 10 }}, 44 {"Time wrong", func(block *types.Block) { block.Time = block.Time.Add(-time.Second * 1) }}, 45 {"NumTxs wrong", func(block *types.Block) { block.NumTxs += 10 }}, 46 {"TotalTxs wrong", func(block *types.Block) { block.TotalTxs += 10 }}, 47 48 {"LastBlockID wrong", func(block *types.Block) { block.LastBlockID.PartsHeader.Total += 10 }}, 49 {"LastCommitHash wrong", func(block *types.Block) { block.LastCommitHash = wrongHash }}, 50 {"DataHash wrong", func(block *types.Block) { block.DataHash = wrongHash }}, 51 52 {"ValidatorsHash wrong", func(block *types.Block) { block.ValidatorsHash = wrongHash }}, 53 {"NextValidatorsHash wrong", func(block *types.Block) { block.NextValidatorsHash = wrongHash }}, 54 {"ConsensusHash wrong", func(block *types.Block) { block.ConsensusHash = wrongHash }}, 55 {"AppHash wrong", func(block *types.Block) { block.AppHash = wrongHash }}, 56 {"LastResultsHash wrong", func(block *types.Block) { block.LastResultsHash = wrongHash }}, 57 58 {"Proposer wrong", func(block *types.Block) { block.ProposerAddress = ed25519.GenPrivKey().PubKey().Address() }}, 59 {"Proposer invalid", func(block *types.Block) { block.ProposerAddress = crypto.Address{} /* zero */ }}, 60 } 61 62 // Build up state for multiple heights 63 for height := int64(1); height < validationTestsStopHeight; height++ { 64 proposerAddr := state.Validators.GetProposer().Address 65 /* 66 Invalid blocks don't pass 67 */ 68 for _, tc := range testCases { 69 block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, proposerAddr) 70 tc.malleateBlock(block) 71 err := blockExec.ValidateBlock(state, block) 72 require.Error(t, err, tc.name) 73 } 74 75 /* 76 A good block passes 77 */ 78 var err error 79 state, _, lastCommit, err = makeAndCommitGoodBlock(state, height, lastCommit, proposerAddr, blockExec, privVals) 80 require.NoError(t, err, "height %d", height) 81 } 82 } 83 84 func TestValidateBlockCommit(t *testing.T) { 85 t.Parallel() 86 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.NewTestingLogger(t), proxyApp.Consensus(), mock.Mempool{}) 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 := types.MakeVote(height, state.LastBlockID, state.Validators, privVals[proposerAddr.String()], chainID) 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, proposerAddr) 108 err = blockExec.ValidateBlock(state, block) 109 _, isErrInvalidCommitHeight := err.(types.InvalidCommitHeightError) 110 require.True(t, isErrInvalidCommitHeight, "expected InvalidCommitHeightError 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, proposerAddr) 116 err = blockExec.ValidateBlock(state, block) 117 _, isErrInvalidCommitPrecommits := err.(types.InvalidCommitPrecommitsError) 118 require.True(t, isErrInvalidCommitPrecommits, "expected InvalidCommitPrecommitsError 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) 127 require.NoError(t, err, "height %d", height) 128 129 /* 130 wrongPrecommitsCommit is fine except for the extra bad precommit 131 */ 132 goodVote, err := types.MakeVote(height, blockID, state.Validators, privVals[proposerAddr.String()], chainID) 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 }