github.com/Oyster-zx/tendermint@v0.34.24-fork/test/e2e/tests/validator_test.go (about) 1 package e2e_test 2 3 import ( 4 "bytes" 5 "testing" 6 7 "github.com/stretchr/testify/require" 8 9 e2e "github.com/tendermint/tendermint/test/e2e/pkg" 10 "github.com/tendermint/tendermint/types" 11 ) 12 13 // Tests that validator sets are available and correct according to 14 // scheduled validator updates. 15 func TestValidator_Sets(t *testing.T) { 16 testNode(t, func(t *testing.T, node e2e.Node) { 17 if node.Mode == e2e.ModeSeed { 18 return 19 } 20 21 client, err := node.Client() 22 require.NoError(t, err) 23 status, err := client.Status(ctx) 24 require.NoError(t, err) 25 26 first := status.SyncInfo.EarliestBlockHeight 27 last := status.SyncInfo.LatestBlockHeight 28 29 // skip first block if node is pruning blocks, to avoid race conditions 30 if node.RetainBlocks > 0 { 31 first++ 32 } 33 34 valSchedule := newValidatorSchedule(*node.Testnet) 35 valSchedule.Increment(first - node.Testnet.InitialHeight) 36 37 for h := first; h <= last; h++ { 38 validators := []*types.Validator{} 39 perPage := 100 40 for page := 1; ; page++ { 41 resp, err := client.Validators(ctx, &(h), &(page), &perPage) 42 require.NoError(t, err) 43 validators = append(validators, resp.Validators...) 44 if len(validators) == resp.Total { 45 break 46 } 47 } 48 require.Equal(t, valSchedule.Set.Validators, validators, 49 "incorrect validator set at height %v", h) 50 valSchedule.Increment(1) 51 } 52 }) 53 } 54 55 // Tests that a validator proposes blocks when it's supposed to. It tolerates some 56 // missed blocks, e.g. due to testnet perturbations. 57 func TestValidator_Propose(t *testing.T) { 58 blocks := fetchBlockChain(t) 59 testNode(t, func(t *testing.T, node e2e.Node) { 60 if node.Mode != e2e.ModeValidator { 61 return 62 } 63 address := node.PrivvalKey.PubKey().Address() 64 valSchedule := newValidatorSchedule(*node.Testnet) 65 66 expectCount := 0 67 proposeCount := 0 68 for _, block := range blocks { 69 if bytes.Equal(valSchedule.Set.Proposer.Address, address) { 70 expectCount++ 71 if bytes.Equal(block.ProposerAddress, address) { 72 proposeCount++ 73 } 74 } 75 valSchedule.Increment(1) 76 } 77 78 require.False(t, proposeCount == 0 && expectCount > 0, 79 "node did not propose any blocks (expected %v)", expectCount) 80 if expectCount > 5 { 81 require.GreaterOrEqual(t, proposeCount, 3, "validator didn't propose even 3 blocks") 82 } 83 }) 84 } 85 86 // Tests that a validator signs blocks when it's supposed to. It tolerates some 87 // missed blocks, e.g. due to testnet perturbations. 88 func TestValidator_Sign(t *testing.T) { 89 blocks := fetchBlockChain(t) 90 testNode(t, func(t *testing.T, node e2e.Node) { 91 if node.Mode != e2e.ModeValidator { 92 return 93 } 94 address := node.PrivvalKey.PubKey().Address() 95 valSchedule := newValidatorSchedule(*node.Testnet) 96 97 expectCount := 0 98 signCount := 0 99 for _, block := range blocks[1:] { // Skip first block, since it has no signatures 100 signed := false 101 for _, sig := range block.LastCommit.Signatures { 102 if bytes.Equal(sig.ValidatorAddress, address) { 103 signed = true 104 break 105 } 106 } 107 if valSchedule.Set.HasAddress(address) { 108 expectCount++ 109 if signed { 110 signCount++ 111 } 112 } else { 113 require.False(t, signed, "unexpected signature for block %v", block.LastCommit.Height) 114 } 115 valSchedule.Increment(1) 116 } 117 118 require.False(t, signCount == 0 && expectCount > 0, 119 "validator did not sign any blocks (expected %v)", expectCount) 120 if expectCount > 7 { 121 require.GreaterOrEqual(t, signCount, 3, "validator didn't sign even 3 blocks (expected %v)", expectCount) 122 } 123 }) 124 } 125 126 // validatorSchedule is a validator set iterator, which takes into account 127 // validator set updates. 128 type validatorSchedule struct { 129 Set *types.ValidatorSet 130 height int64 131 updates map[int64]map[*e2e.Node]int64 132 } 133 134 func newValidatorSchedule(testnet e2e.Testnet) *validatorSchedule { 135 valMap := testnet.Validators // genesis validators 136 if v, ok := testnet.ValidatorUpdates[0]; ok { // InitChain validators 137 valMap = v 138 } 139 return &validatorSchedule{ 140 height: testnet.InitialHeight, 141 Set: types.NewValidatorSet(makeVals(valMap)), 142 updates: testnet.ValidatorUpdates, 143 } 144 } 145 146 func (s *validatorSchedule) Increment(heights int64) { 147 for i := int64(0); i < heights; i++ { 148 s.height++ 149 if s.height > 2 { 150 // validator set updates are offset by 2, since they only take effect 151 // two blocks after they're returned. 152 if update, ok := s.updates[s.height-2]; ok { 153 if err := s.Set.UpdateWithChangeSet(makeVals(update)); err != nil { 154 panic(err) 155 } 156 } 157 } 158 s.Set.IncrementProposerPriority(1) 159 } 160 } 161 162 func makeVals(valMap map[*e2e.Node]int64) []*types.Validator { 163 vals := make([]*types.Validator, 0, len(valMap)) 164 for node, power := range valMap { 165 vals = append(vals, types.NewValidator(node.PrivvalKey.PubKey(), power)) 166 } 167 return vals 168 }