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.

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