github.com/vipernet-xyz/tm@v0.34.24/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/vipernet-xyz/tm/test/e2e/pkg"
    10  	"github.com/vipernet-xyz/tm/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  }