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.

172 lines
4.8 KiB

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