You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

180 lines
5.1 KiB

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